js笔记
1.如需使用外部文件,请在<script> 标签的 "src" 属性中设置该 .js 文件。(外部调用js.html)
注意:外部脚本不能包含 <script> 标签。
2.//后面的内容为注释内容
/*
还可以进行多行注释
*/
3.JavaScript 语言中 , 定义一个常量 推荐 使用 全大写字母 和 下划线 来命名 , 该规则 不是强制的 , 但是 推荐使用 ;
const MY_NAME = "Tom";
4.可以在文本字符串中使用反斜杠对代码行进行换行。
document.write("你好
世界!");
5.一条语句中声明的多个不可以赋同一个值:
var x,y,z=1;
x,y 为 undefined, z 为 1。
6.如果重新声明 JavaScript 变量,该变量的值不会丢失:
在以下两条语句执行后,变量 carname 的值依然是 "Volvo":
var carname="Volvo";
var carname;
7.JavaScript 只有一种数字类型。数字可以带小数点,也可以不带:
var x1=34.00; //使用小数点来写
var x2=34; //不使用小数点来写
极大或极小的数字可以通过科学(指数)计数法来书写:
var y=123e5; // 12300000
var z=123e-5; // 0.00123
8.创建数组的方法
var cars=new Array();
cars[0]="Saab";
cars[1]="Volvo";
cars[2]="BMW";
或者:
var cars=new Array("Saab","Volvo","BMW");
或者!!!:
var cars=["Saab","Volvo","BMW"];
9.对象(Python的字典!)由花括号分隔。在括号内部,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号分隔:
var person={firstname:"John", lastname:"Doe", id:5566};
字典有两种寻址方式:
name=person.lastname;
name=person["lastname"];
10.Undefined 这个值表示变量不含有值。可以通过将变量的值设置为 null 来清空变量。
cars=null;
person=null;
11.为什么在f12界面写的js代码不会被执行?
当你打开网页的那一瞬间,你本地的代码就已经执行了,而你修改后的代码,只是修改了,实际上不会被浏览器识别,在html修改相当于只是文本修改,要执行的话要写在源代码或者你写在控制台,让浏览器识别为可执行代码才行
12.JavaScript 可以通过不同的方式来输出数据:
使用 window.alert() 弹出警告框。
使用 document.write() 方法将内容写到 HTML 文档中。
使用 innerHTML 写入到 HTML 元素。
使用 console.log() 写入到浏览器的控制台。
13.向未声明的js变量赋值:
var var1 = 1; // 不可配置全局属性
var2 = 2; // 没有使用 var 声明,可配置全局属性
console.log(this.var1); // 1
console.log(window.var1); // 1
delete var1; // false 无法删除
console.log(var1); //1
delete var2;
console.log(delete var2); // true
console.log(var2); // 已经删除 报错变量未定义
总结:若向未声明的变量赋值,则该变量可以被删除。delete a
14.在 HTML 中, 全局变量是 window 对象: 所有数据变量都属于 window 对象
//此处可使用 window.carName
function myFunction() {
carName = "Volvo";
}
总结:若在函数内定义了一个局部变量,则在该函数的外面(上下不限)都可以通过window.变量名 来使用该变量
15.行内执行js代码
(省去了定义函数)
16.常见的HTML事件
onchange HTML 元素改变
onclick 用户点击 HTML 元素
onmouseover 用户在一个HTML元素上移动鼠标
onmouseout 用户从一个HTML元素上移开鼠标
onkeydown 用户按下键盘按键
onload 浏览器已完成页面的加载
更多详细事件可以查询http://www.it028.com/dom-obj-event.html
HTML 事件属性可以直接执行 JavaScript 代码
HTML 事件属性可以调用 JavaScript 函数
17.通常, JavaScript 字符串是原始值,可以使用字符创建: var firstName = "John"
但也可以使用 new 关键字将字符串定义为一个对象: var firstName = new String("John")
var x = "John";
var y = new String("John");
typeof x // 返回 String
typeof y // 返回 Object
(x === y) // 结果为 false,因为 x 是字符串,y 是对象
=== 为绝对相等,即数据类型与值都必须相等。
注意:这里是三个等号
18.原始值字符串,如 "John", 没有属性和方法(因为他们不是对象)。
原始值可以使用 JavaScript 的属性和方法,因为 JavaScript 在执行方法和属性时可以把原始值当作对象。
19.对于if-else语句语法比较像c语言。
20.js也有switch语句,与c相同
21.for循环与c相同.
22.JavaScript中可以使用for-in语句(与Python不同!!!!)
a=[1,2,5,8,9,10]
for(x in a){
console.log(a[x])
}
//这里的x分别为0 1 2 3 4 5,而不是a的元素
person={"name":"John","age":18}
for(x in person){
console.log(x)
}
//这种方法可以输出键名
23.while/do-while与C相同
24.我们可以对 JavaScript 语句进行标记。如需对语句(块)进行标记,请在语句前加上冒号“:”
name:
语句
语句,也可以是语句块,用大括号括起来。
这种操作可以配合break和continue语句进行食用
break name;(可以对普通语句块使用)
continue name;(只能对循环语句使用,普通语句块不行)
25.可以用typeof来检测变量的数据类型(和c一样)
26.在 JavaScript 中 null 表示 "什么都没有"。用 typeof 检测 null 返回是object。
你可以设置为 null 来清空对象:
console.log(typeof null)//object
var i = 10;
console.log(typeof i)//number
i=null
console.log(typeof i)//object
用null给变量赋值可以起到清空变量的值的作用,也会把变量的类型变为object
27.在 JavaScript 中, undefined 是一个没有设置值的变量。
var person = undefined; // 值为 undefined, 类型为 undefined
typeof 一个没有值的变量会返回 undefined
任何变量都可以通过设置值为 undefined 来清空。 类型为 undefined
28.null与undefined的区别:
null和undefined的值相等,但类型不相等。
a=null;//object
b=undefined;//undefined
console.log(ab)//true
console.log(a=b)//false
1.定义:
(1)undefined:是所有没有赋值变量的默认值,自动赋值。
(2)null:主动释放一个变量引用的对象,表示一个变量不再指向任何对象地址。
2.何时使用null?
当使用完一个比较大的对象时,需要对其进行释放内存时,设置为null。
3.null与undefined的异同点:
(1)undefined--表示变量声明过但没有赋过值。它是所有未赋值变量的默认值。
var a; // a 自动被赋值为 undefined
(2)null--表示一个变量将来可能指向一个对象,一般用于主动释放变量。(主动释放指向对象的引用)
var emps = ['ss','nn'];
emps = null; // 释放指向数组的引用
29.JavaScript中有变量提升的概念,即在代码执行之前,变量和函数的声明会被提升到作用域的顶部。
这意味着你可以在声明之前使用变量和函数,而不会引发错误。(var定义)
而用let定义则和正常一样,不会出现变量提升的情况。所以要根据实际情况来决定用什么定义
(JavaScript 只有声明的变量会提升,初始化的不会。)
var x = 5; // 初始化 x
30.在JavaScript中有6种不同的数据类型:
string
number
boolean
object
function
symbol
3种对象类型:
Object
Date
Array
2个不包含任何值的对象类型:
null
undefined
//如果对象是 JavaScript Array 或 JavaScript Date ,我们就无法通过 typeof 来判断他们的类型,因为都是 返回 object。
31.可以使用constructor 属性返回所有 JavaScript 变量的构造函数。(可以用于判断typeof判断不了的Date和Array类型)
"John".constructor // 返回函数 String() { [native code] }
(3.14).constructor // 返回函数 Number() { [native code] }
false.constructor // 返回函数 Boolean() { [native code] }
[1,2,3,4].constructor // 返回函数 Array() { [native code] }
{name:'John', age:34}.constructor // 返回函数 Object() { [native code] }
new Date().constructor // 返回函数 Date() { [native code] }
function () {}.constructor // 返回函数 Function(){ [native code] }
32.JavaScript中的类型转化
(1)使用对应的方法转换
String(data)可以将数据转换为字符串
Number(data)可以将数据转化为数字类型
parseFloat(data)解析字符串并返回浮点数。
parseInt(data)解析字符串并返回整数。
Number 方法 toString() 也是有同样的效果。
a=123
console.log(typeof a.toString())//string
当尝试将字符串"abc"转化成数字类型时,结果会是NaN。NaN 是 JavaScript 中的一个特殊值,表示 "不是一个有效的数字"。它并不是真正的数字,而是用来表示 数字转换失败 的情况。
NaN的特点:
NaN 是 number 类型(typeof NaN === "number")。
NaN 不等于任何值,包括它自己(NaN === NaN 返回 false)。
可以用 isNaN() 或 Number.isNaN() 检测 NaN:
console.log(isNaN(NaN)); // true
console.log(Number.isNaN(NaN)); // true
33.关于列表:
var list = []
var list=New Array(num) num默认为0
1.添加元素
list.unshift(元素)//从前往后
list.push()//在尾部新增一个元素
list.splice(start, deleteCount, item1, item2, ...)
start 是开始操作的数组下标。deleteCount 是要移除的数组元素的数量。如果设置为0,则不会移除元素。item1, item2, ... 是要添加进数组的元素,从start位置开始。
2.删除元素
list.pop()//删除最后的元素
list.shift()//删除开头元素
list[num].remove//删除指定元素
3.查找元素
list.indexOf()//查找元素,返回其在列表中的索引值.不存在时返回-1
4.元素倒置(反转)
list.reverse()
5.列表切割
list.slice(索引值[,索引值])
若括号内只有一个索引值,则会把索引值之前的所有元素全部割舍
若括号内有两个索引值,则会截取两个索引值之间的部分
6.获取列表长度
list.length
splice函数
splice(起始位置,删除元素的个数,[增加的元素,...])
join方法可以把列表中的所有元素放入字符串
var str=list.join(",")//以逗号为分隔
34.if后面只有一条语句时可以不用{},但要进行缩进,不能直接写在if那一行
35.先定位标签,然后在js函数里return false可以终止a标签本来具有的跳转功能。(js代码的执行优先于a标签的跳转功能)
36.JavaScript关键字this使脚本能够根据使用这个关键字的上下文将值传递给函数。在"对用户进行重定向.html"示例中,this是在一个由标签的事件触发的函数中使用的,所以this是一个链接对象。
this从HTML链接获得URL(也就是a标签的href属性值)
在事件处理函数中,this 指向触发事件的 DOM 元素(即被点击的导航项 div)
37.定义箭头函数
(name)=>{函数体}
38.getElementsBy 包含动态添加的内容
querySelector 不包含动态添加内容
39."`"也可以用作字符串符号(与单引号双引号差不多,不过可以写多行代码,更高级,一般用于在js中写html代码
40.在JavaScript中const关键字用于声明常量变量,其值在程序运行期间不可重新赋值。
用途包括:1)防止变量重新赋值;2)标识不变的常数。
其语法为:const variablename = value。
41.new关键字可以创建一个新的对象实例
42.XMLHttpRequest 是 JavaScript built-in 的一个 class,用于发送 HTTP 请求,俗称 AJAX。
43.if(top.location!=self.location){//检测顶部窗口是否为本窗口
top.location.replace(self.location)//如果不是,则把顶部窗口替换为本窗口(在浏览历史的部分也会替换,因此back按钮无效)
}
44.通过改变a标签target的目标来实现改变iframe内的网页
window.onload = initLinks;
function initLinks(){
for(var i=0;i<document.links.length;i++){
document.links[i].target = "icontent";//目标为iframe的id
}
}
通常只需要设置iframe的id就可以了,不过有些浏览器要求使用name属性(如Firefox和IE)
45.document对象代表当前加载的html文档,提供方法和属性来与页面元素交互、获取信息和修改内容。关键方法和属性包括:getelementbyid(按id获取元素)、createelement(创建元素)、appendchild(追加元素)、body(文档内容部分)、documentelement(html文档根元素)、title(获取/设置标题)、url(获取文档url)。
46.在JavaScript中,ContentWindow属性用于访问嵌入式框架(iframe)的窗口对象。
47.return false可以阻止函数结束之后的下一步操作(例如a标签本身的跳转操作)
48.关于作用域
function test(){
console.log(a);
}
var a=10;
a与test()都属于全局作用域。函数的函数体属于函数作用域。上面例子中,全局作用域里面嵌套了一个函数作用域。在函数作用域里面可以访问全局作用域中的变量,但是反过来不行
函数作用域里面的a会先去当前函数作用域里寻找是否有一个变量a。如果找不到,就去上一层包着它的父级作用域中寻找
49.函数的第二种定义方法
var a=function(){
document.write("This is My Second Function!");
}
a();
50.修改css样式中的background-color属性
this.style.backgroundColor = "rgb(64,64,64)"
51.变量定义
var 定义全局变量。其定义的变量可在函数外任何位置通过window.变量名调用
let 定义块级变量,定义的变量仅在函数内生效
const 定义的变量不可修改,const除了具有let的特征外,const定义的变量,一旦定义必须立即赋值,且之后不可修改,也就是常量;
52.querySelector获取第一个符合条件的元素
querySelector获取全部符合条件的元素
53.现代浏览器支持自定义元素
以 data- 开头的属性是 HTML5 提供的自定义数据属性
例如:
在js代码中,可以通过this.dataset属性来访问所有 data-* 属性
它会自动将 data- 后面的属性名转换为驼峰式命名
例如:
js:
window.location.href = this.dataset.url;
补充:(闭坑)(请务必记下来!!!)dataset的命名转换细节
使用dataset报错undefind
1. 连字符处理
多个连字符会采用驼峰命名法,转换为单一大写字母
<div data-vehicle-engine-type="turbo"></div>
console.log(vehicle.dataset.vehicleEngineType); // "turbo"
2. 大写字母处理
在保持第1条中的驼峰命名法的基础上,HTML中的大写会被转为小写
<div data-API-KEY="abc123"></div>
console.log(api.dataset.apiKey); // "abc123"
报错实例分析(本人的):
原报错代码
<input type="hidden" id="get_registerURL" data-url_passRegister="{% url 'pass_register'%}">
对应js
// 获取目标url接口
const url_Register = document.getElementById("get_registerURL").dataset.url_passRegister;
console.log("请求地址:",url_Register);
此时url_Register的值为undefind。即,没有从dataset中获取到值。
原因分析:根据大写字母处理原则,报错代码中定义的属性data-url_passRegister被转换后应该为url_passregister(R变成小写)。
- 给元素绑定事件
element.onmouseover=function(e){
this.style.background = "white;
}
其中,e是标准浏览器传递进去的事件参数.
这个是js的event, 表示正在处理的部分,或者说处于active状态的部分
e 不是关键字, arguments 是关键字 e === arguments[0] - 反引号(`)允许js在字符串中引用变量。类似于Python的
f"字符串{value}"
Hello ${ name } - 修改iframe中的JS
// 获取iframe元素
const myIframe = document.getElementById('myIframe');
// 访问iframe内部的window对象
const iframeWindow = myIframe.contentWindow;//js
// 调用iframe内部定义的函数
iframeWindow.someFunctionDefinedInIframe();
// 这两种方式是等价的
const doc1 = iframe.contentWindow.document;
const doc2 = iframe.contentDocument;
解析:
可以通过获取iframe元素的window对象来达到修改iframe中的js的目的
什么是window对象?
window 对象是浏览器 JavaScript 的全局对象
window对象的基本特性:
- 全局作用域:在浏览器中,所有全局变量和函数都是 window 对象的属性和方法
- 顶级对象:DOM 中的 document 对象是 window 的一个属性
- 跨窗口通信:通过 window 可以访问其他框架或窗口
57 JavaScript 中的 await 关键字
await 是 JavaScript 中用于处理异步操作的关键字,它是 async/await 语法的一部分,使得异步代码的编写和阅读更像同步代码。
主要作用
- 暂停异步函数的执行:
await会暂停当前async函数的执行,等待 Promise 完成 - 获取 Promise 的解决值:当 Promise 解决(resolve)后,
await会返回 Promise 的解决值 - 简化异步代码:避免了回调地狱,使异步代码更易读和维护
使用规则
await只能在标记为async的函数内部使用await后面通常跟随一个 Promise 对象- 如果
await后面是非 Promise 值,它会将该值转换为已解决的 Promise
示例
async function fetchData() {
// 等待fetch返回的Promise解决
const response = await fetch('https://api.example.com/data');
// 等待response.json()返回的Promise解决
const data = await response.json();
return data;
}
// 使用
fetchData().then(data => console.log(data));
错误处理
可以使用 try/catch 来捕获 await 表达式中 Promise 被拒绝(reject)的情况:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('获取数据失败:', error);
}
}
await 使得异步代码的流程控制更加直观,是现代 JavaScript 中处理异步操作的首选方式之一。
function 函数名称(){}
声明函数,函数名称首字母大写比较好些
在函数中,如果仅仅希望退出函数时 ,也可使用 return 语句。返回值是可选的:
if (a>b)
{
return;
}
var 变量名
JavaScript 使用关键字 var 来定义变量, 使用等号来为变量赋值:
声明一个变量有两种方式:
第一种:var num=1。如果在方法中声明,则为局部变量;如果在全局中声明,则为全局变量
第二种:num=1。事实上这是对属性进行赋值操作。首先,它会尝试在当前作用域链(如果在方法中声明,则当前作用域代表全局作用域和方法局部作用域)中解析num,如果在任何当前作用域链中找到num,则会对num属性进行赋值,如果没有找到num,他会在全局对象(即当前作用域链的最顶层对象,如window对象)中创造num属性并赋值
注意!它并不是声明了一个全局变量,而是创建了一个全局对象的属性
由于变量声明自带不可删除属性,比较var num=1跟num=1,前者是变量声明,带不可删除
属性,因此无法被删除;后者为全局变量的一个属性,因此可以从全局变量中删除。
window:
所有以window.开始的语句,都可以直接把window省略。只是在有些软件中,由于其编译器特性,当你写了window.的时候会自动的出现window的方法,所以window没必要写!
.alert()
弹出警告框。
括号内可以写字符串,也可以写表达式
.onload
可以用来“等网页加载完之后”触发某函数。
window.onload = initAll //这里的initAll为自定义函数名。因为大型网页可能要加载一段时间,如果不加上的话可能会出现找不到标签的情况。
innerHTML 写入到 HTML 元素。
console.log()
写入到浏览器的控制台。方便调试时查看变量等的值(在f12的console中查看)
document:
.write()
将内容写到 HTML 文档中。
注意:若是在文档加载完成后执行该动作,会清空文档
document对象中有innerHTML、innerText这两个属性,都是获取document对象文本内容,但使用起来还是有区别的;
(记得先选中元素)document.getElementById("demo").innerHTML = "段落已修改。";
1) innerHTML设置或获取标签所包含的HTML+文本信息(从标签起始位置到终止位置全部内容,包括HTML标签,但不包括自身)
2) outerHTML设置或获取标签自身及其所包含的HTML+文本信息(包括自身)
3) innerText设置或获取标签所包含的文本信息(从标签起始位置到终止位置的内容,去除HTML标签,但不包括自身)
4) outerText设置或获取标签自身及其所包含的文本信息(包括自身)
参考"./附件/图片1.jpeg"
createElement("标签名")
创造一个空的标签名,是一个标签对象(可以对该标签对象做innerHTML等操作)
images
返回当前文档中所有图片的数组
.parentNode
返回包围它的容器标签
.tagName
返回容器标签的名称
例如: xxx.tagName == "A" //判断是否为a标签
(tagName总是返回大写的值)
.length
返回这个数组的长度(图片的数量)
.属性值 = new Image()
可以新建属性值并赋值新的图片对象。
.onmouseout/.onmouseover = 函数
当鼠标离开/停留 元素上时,触发某事件
links
返回一个文档中所有具有 href 属性值的 元素与 元素的数组
querySelectorAll("CSS选择器"): 根据CSS选择器获取元素
详见"获取元素"
字符串属性
.length
内置函数,计算字符串长度
var txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var sln = txt.length;
.constructor
返回创建字符串属性的函数
var txt = "Hello World!";
document.write(txt.constructor);
输出:
function String() { [native code] }
typeof
返回数据的类型
typeof "John"
结果输出String
字符串方法
charAt() 返回指定索引位置的字符
charCodeAt() 返回指定索引位置字符的 Unicode 值
concat() 连接两个或多个字符串,返回连接后的字符串
fromCharCode() 将 Unicode 转换为字符串
indexOf() 返回字符串中检索指定字符第一次出现的位置
lastIndexOf() 返回字符串中检索指定字符最后一次出现的位置
localeCompare() 用本地特定的顺序来比较两个字符串
match() 找到一个或多个正则表达式的匹配
replace() 替换与正则表达式匹配的子串
search() 检索与正则表达式相匹配的值
slice() 提取字符串的片断,并在新的字符串中返回被提取的部分
split() 把字符串分割为子字符串数组
substr() 从起始索引号提取字符串中指定数目的字符
substring() 提取字符串中两个指定的索引号之间的字符
toLocaleLowerCase() 根据主机的语言环境把字符串转换为小写,只有几种语言(如土耳其语)具有地方特有的大小写映射
toLocaleUpperCase() 根据主机的语言环境把字符串转换为大写,只有几种语言(如土耳其语)具有地方特有的大小写映射
toLowerCase() 把字符串转换为小写
toString() 返回字符串对象值
toUpperCase() 把字符串转换为大写
trim() 移除字符串首尾空白
valueOf() 返回某个字符串对象的原始值
includes("str") 判断某个值是否存在于字符串或数组中。
confirm(str)
confirm()方法有一个参数(向用户询问的问题)若用户选择OK则返回true,选择canccel返回false
prompt(str,str)
let a = prompt("你今天想吃啥?","")
prompt()函数可以获取用户的回复。
当用户点击了cancel按钮或没有输入直接选择OK时,会返回null值。关于null和undefined详见上面。
Chrome和Firefox允许访问者禁止页面创建其他对话框
对html标签/元素的属性:
.addEventListener(条件,回调(函数))
标签.addEventListener("click",alert("被点击了"))
关于“条件”详见:JavaScript中可供监听的条件
.click()
点击该元素
.style.background="red"
改变标签的css样式,background应该可以换成其他css属性
.appendChild("标签")把标签插入到目标html标签下
.classList DOM 元素类名的操作接口
.remove('active') 移除指定类
.remove('class1', 'class2');删除多个类
.add('active') 添加指定类
.add('class1', 'class2', 'class3');添加多个类
.toggle('active') 切换类名(存在则移除,不存在则添加)
.toggle('active', true); // 强制添加
.toggle('active', false); // 强制删除
.contains() 检查是否包含指定类名(包含返回true,否则返回false)
.replace('old-class', 'new-class') 替换类名
.item(0) 返回指定索引的类名(索引从0开始)
.toString() 返回类列表的字符串表示
.forEach(className => {}) 遍历所有类名
.keys(), .values(), .entries() 迭代器方法
.getAttribute('id等属性值') 获取元素指定属性对应的值
.dataset.自定义属性 获取自定义属性的值
fetch(目标url,请求的参数)
element
.children
返回所有直接子元素(不包括文本节点和注释节点,仅元素节点)。
获取元素
.closest("form") 获取父级form元素 关键字:上一层、上
.querySelector(): 获取第一个匹配的子元素
.querySelectorAll(): 获取所有匹配的子元素
.children: 获取所有直接子元素(仅元素节点)
.firstElementChild :获取第一个子元素
.nextElementSibling:获取后一个兄弟元素
.previousElementSibling:获取前一个兄弟元素
```js
const form = document.querySelector("form");
// 获取第一个 input 子元素
const firstInput = form.querySelector("input");
// 获取所有 input 子元素
const allInputs = form.querySelectorAll("input");
// 获取所有直接子元素(仅元素节点)
const childElements = form.children;
```
| 特性 | 属性/方法 | 返回内容 | 返回类型 | 是否实时 | 主要用途 |
|---|---|---|---|---|---|
| 全面子节点 | element.childNodes |
所有类型子节点 | NodeList | 是 需要处理文本、注释等所有节点时 | |
| 元素子节点 | element.children |
所有元素子节点 | HTMLCollection 是 | 最常用,只想获取子标签时 | |
| 首尾节点 | element.firstChild/lastChild |
第一个/最后一个子节点(任何类型) | Node | 是 | 需要获取首尾节点(不介意是文本节点时) |
| 首尾元素 | element.firstElementChild/lastElementChild |
第一个/最后一个子元素节点 Element | 是 | 更常用,直接获取首尾子标签 | |
| CSS选择(单) | element.querySelector(selector) |
匹配选择器的第一个后代元素 | Element | 否 | 使用 CSS 选择器精确查找一个子元素 |
| CSS选择(所有) | element.querySelectorAll(selector) |
匹配选择器的所有后代元素 | NodeList | 否 | 使用 CSS 选择器精确查找一组子元素 |
注:用element.children方法返回的是一个 HTMLCollection,而不是数组(Array)。它本身没有 forEach 方法。forEach 是 Array 原型上的方法
document.querySelectorAll(它返回一个 NodeList),而现代浏览器中的 NodeList 拥有 forEach 方法。
解决方法:
- 使用
Array.from()方法转换为数组
document.addEventListener('DOMContentLoaded', function() {
const sidebar_functions = document.getElementsByClassName("function");
// 将 HTMLCollection 转换为真正的数组
Array.from(sidebar_functions).forEach(element => {
element.addEventListener("click", function() {
const text = this.querySelector("h2");
console.log(text);
});
});
});
- 使用传统的
for循环
document.addEventListener('DOMContentLoaded', function() {
const sidebar_functions = document.getElementsByClassName("function");
// 使用传统的 for 循环
for (let i = 0; i < sidebar_functions.length; i++) {
sidebar_functions[i].addEventListener("click", function() {
const text = this.querySelector("h2");
console.log(text);
});
}
});
JSON
.parse(data) 解包json数据,把json类型转化为字典 #注:如果发现转换之后仍为字符串,请检查是否对该对象进行了多次json编码
.stringify(data) 将整个json对象转化为字符串
时间对象 Date 获取当前时间
const currentTime = new Date();
//返回的类型是number
const year = currentTime.getFullYear();
const month = currentTime.getMonth() + 1; // 月份从0开始,因此需要加1
const day = currentTime.getDate();
const hours = currentTime.getHours();
const minutes = currentTime.getMinutes();
const seconds = currentTime.getSeconds();
console.log(year, month, day, hours, minutes, seconds);
setTimeout 延时触发函数
方法1:
function myFunction() {
console.log("10 分钟后执行!");
}
// 10 分钟 = 10 × 60 × 1000 毫秒
const tenMinutesInMs = 10 * 60 * 1000;
// 10 分钟后执行 myFunction
setTimeout(myFunction, tenMinutesInMs);
方法2:
setTimeout(() => {
console.log("10 分钟后执行!");
}, 10 * 60 * 1000); // 10 分钟 = 600,000 毫秒
下面进入markdown区
setInterval() 是一个JavaScript定时器函数,它会重复执行指定的回调函数
// 定义一个函数,打印当前时间
function printTime() {
const now = new Date();
console.log("当前时间:", now.toLocaleTimeString());
}
// 每隔 1000 毫秒(1秒)执行一次 printTime
const intervalId = setInterval(printTime, 1000);
// 10 秒后停止定时器
setTimeout(() => {
clearInterval(intervalId); // 停止 setInterval
console.log("定时器已停止");
}, 10000);
Chart.js --绘图模块
1.导入模块
- 通过CDN引入
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> - 通过npm安装到本地
npm install chart.js
2.基本用法
-
折线图
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'line', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [{ label: 'Monthly Sales', data: [65, 59, 80, 81, 56, 55, 40], backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); </script> </body> </html> -
柱状图
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); </script> </body> </html> -
饼图
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'pie', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { responsive: true } }); </script> </body> </html> -
雷达图
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'radar', data: { labels: ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'], datasets: [{ label: 'My First Dataset', data: [65, 59, 90, 81, 56, 55, 40], fill: true, backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgb(255, 99, 132)', pointBackgroundColor: 'rgb(255, 99, 132)', pointBorderColor: '#fff', pointHoverBackgroundColor: '#fff', pointHoverBorderColor: 'rgb(255, 99, 132)' }] }, options: { scales: { r: { suggestedMin: 0, suggestedMax: 100 } } } }); </script> </body> </html> -
极坐标图
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'polarArea', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { responsive: true } }); </script> </body> </html> -
散点图
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'scatter', data: { datasets: [{ label: 'Scatter Dataset', data: [{ x: -10, y: 0 }, { x: 0, y: 10 }, { x: 10, y: 5 }], backgroundColor: 'rgb(255, 99, 132)' }] }, options: { scales: { x: { type: 'linear', position: 'bottom' } } } }); </script> </body> </html>
3.高级用法
-
动态更新数据(值更新,数据数量不更新)
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <button onclick="updateData()">Update Data</button> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'line', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [{ label: 'Monthly Sales', data: [65, 59, 80, 81, 56, 55, 40], backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } } } }); function updateData() { myChart.data.datasets[0].data = [30, 40, 50, 60, 70, 80, 90]; myChart.update(); } </script> </body> </html> -
动态更新数据(数据的数量随时间而增加)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <canvas id="myChart"></canvas> </body> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-streaming@2.0.0/dist/chartjs-plugin-streaming.min.js"></script> <script> const labels = []; let data = { labels:labels, datasets:[{ label:"温度", backgroundColor: 'rgb(255,99,132)', borderColor: 'rgb(255,99,132)', data:[], }] }; const config = { type:'line', data:data, options:{} }; // 修改config选项 --deepseek // const config = { // type: 'line', // data: data, // options: { // animation: { // duration: 0 // 禁用动画以获得即时更新 // }, // scales: { // x: { // type: 'realtime', // 使用实时比例尺 // realtime: { // duration: 20000, // 显示最近20秒的数据 // refresh: 1000, // 每秒刷新一次 // delay: 1000, // onRefresh: chart => { // // 这里可以添加数据更新逻辑 // } // } // } // } // } // }; const myChart = new Chart( document.getElementById("myChart"), config ); // 需要传一个温度参数 function updateData(temperature){ const nowTime = new Date(); const hours = nowTime.getHours().toString(); const minutes = nowTime.getMinutes().toString(); const seconds = nowTime.getSeconds().toString(); const time = `${hours}:${minutes}:${seconds}`; labels.push(time) // console.log("收到温度数据"+temperature) myChart.data.datasets[0].data.push(temperature) myChart.update(); } // 流式传输区 const eventSource = new EventSource('/output-jsonresponse'); eventSource.addEventListener('message', (event) => { data = JSON.parse(event.data);//解包json数据 console.log('收到信息:', data); console.log("数据类型:"+typeof data) console.log("温度数据"+data["temperature"]); // 每分钟刷新一次数据 updateData(data["temperature"]); // setInterval(updateData(data.temperature),1000); }); eventSource.addEventListener('error', (event) => { if (event.eventPhase === EventSource.CLOSED) { console.log('Connection was closed.'); } else { console.error('An error occurred:', event); } }); </script> </html> -
事件处理
Chart.js 支持事件处理,可以监听图表上的点击、悬停等事件,实现交互式效果。
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { scales: { y: { beginAtZero: true } }, onClick: (event, elements) => { if (elements.length > 0) { const index = elements[0].index; alert(`Clicked on ${myChart.data.labels[index]} with value ${myChart.data.datasets[0].data[index]}`); } } } }); </script> </body> </html> -
多个数据集
Chart.js 支持在一个图表中绘制多个数据集,可以用来比较不同数据之间的关系。
<!DOCTYPE html> <html> <head> <title>Chart.js Example</title> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> </head> <body> <canvas id="myChart" width="400" height="400"></canvas> <script> const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'line', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [ { label: 'Sales', data: [65, 59, 80, 81, 56, 55, 40], backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgba(255, 99, 132, 1)', borderWidth: 1 }, { label: 'Expenses', data: [28, 48, 40, 19, 86, 27, 90], backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1 } ] }, options: { scales: { y: { beginAtZero: true } } } }); </script> </body> </html>
动态提交form表单
function chileElement(){
let menu = document.getElementsByClassName("child");
for(let i=0;i<menu.length;i++){
menu[i].onmouseover = function(e){
this.style.backgroundColor = "rgb(219, 234, 254)";
this.style.opacity = 1;
}
menu[i].onmouseout = function(e){
this.style.backgroundColor = "rgb(249, 251, 255)";
this.style.opacity = 1;
}
menu[i].onclick = function(){
// // 清空现有数据。因为在
// const iframeWindow = document.getElementsByClassName("outcome")[0].children[0].contentWindow;
// iframeWindow.document.getElementById('data-display').innerHTML = '';
// 提交日期数据
const form = this.closest("form");
form.action = document.getElementById("history").dataset.target;
// 添加CSRF Token
const csrfToken = getCookie('csrftoken');
const csrfInput = document.createElement('input');
csrfInput.type = 'hidden';
csrfInput.name = 'csrfmiddlewaretoken';
csrfInput.value = csrfToken;
form.appendChild(csrfInput);
// 上传表单
form.submit();
}
}
}
// 获取cookie
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.startsWith(name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
动态上传数据(非表单形式)
// 上传数据函数,第一个参数为url接口,第二个参数为要上传的字典
async function uploadDictionary(url,dict) {
// 获取 CSRF token
const csrftoken = getCookie('csrftoken');
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken // 添加 CSRF token 到请求头
},
body: JSON.stringify(dict) // 将字典转为JSON字符串
});
const result = await response.json();
console.log('上传成功:', result);
return result;
} catch (error) {
console.error('上传失败:', error);
throw error;
}
}
// 获取 CSRF token 的函数
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 判断 cookie 名称是否匹配
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
数据上传
const auto_data = {"auto_data":"true"};
url = this.dataset.url;
uploadDictionary(url,auto_data);
用变量作为字典的键名
如果你想将一个变量作为字典的键值的话
- 错误示例:
const key = this.id;
donst data = {key:"true"};
最终得到的值为
{"key":"true"}
原因分析:{key : "true"} 会创建一个固定键名 "key" 的对象,而不是动态使用 key 变量的值。
所以应使用 [] 动态设置对象的键名
-正确示例:
const key = this.id;
donst data = {[key]:"true"};
Fetch API 网络请求详细指南
fetch!(供Ctrl+F定位使用)
1.基本语法
fetch(url [, options])
.then(response => {
// 处理响应
})
.catch(error => {
// 处理错误
});
2.GET 请求示例
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
3.响应处理
3.1 常用响应方法
.json()- 解析为JSON.text()- 解析为文本.blob()- 解析为Blob对象
3.2 常用响应属性
response.ok- 请求是否成功response.status- HTTP状态码
3.3 完整响应处理
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error(error));
补充说明:两个then的作用
第一个 .then(response => response.json())
作用: 处理原始的 HTTP 响应对象,将其转换为 JSON 格式的数据
-
response 参数是 Fetch API 返回的原始响应对象
-
response.json() 是一个方法,它读取响应体并将其解析为 JSON
-
这个方法返回一个 Promise,所以需要下一个 .then() 来处理解析后的数据
第二个 .then(data => console.log(data))
作用: 处理已经解析为 JavaScript 对象的 JSON 数据
-
data 参数是前一个 .then() 中 response.json() 解析后的 JavaScript 对象
-
在这里你可以对获取到的数据进行操作(这里只是简单地在控制台输出)
完整流程解析
-
fetch() 发起请求,返回一个 Promise
-
第一个 .then() 接收原始响应,调用 .json() 方法解析响应体
-
.json() 返回另一个 Promise,解析完成后进入第二个 .then()
-
第二个 .then() 接收解析后的数据对象
-
.catch() 捕获整个链中可能发生的任何错误
为什么需要两个 .then()
因为 Fetch API 的设计是分阶段的:
第一阶段获取原始响应(包括状态码、头部等)
第二阶段提取并解析响应体内容(如 JSON、文本等)
这种设计使得开发者可以在第一个 .then() 中检查响应状态(如 response.ok)后再决定是否解析内容。
补充:fetch...then...catch语句的语法格式
fetch(url){
// 代码块
}.then(response => { 代码块 })
.then(data => {})
[...] // 可以有一个或多个then
.catch(error => {
console.log(error);
})
4 POST 请求示例
fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: 'value' })//将字典转化为json字符串
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
5 请求选项配置
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data),
mode: 'cors',
credentials: 'include'
}
6 错误处理机制
fetch('https://api.example.com/missing')
.then(response => {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
return response.json();
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
} else {
console.error('请求错误:', error);
}
});
7 取消请求
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 5000);
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.catch(error => {
if (error.name === 'AbortError') {
console.log('请求被取消');
}
});
8 文件上传
const formData = new FormData();
// 注:fileInput是一个<input type="file">的标签
// "file" 是服务器端用来识别这个数据的键(key) 或字段名。详细看下面补充
formData.append('file', fileInput.files[0]);
fetch('https://api.example.com/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
补充:
fileInput.files返回的是一个文件列表对象(FileList)。当用户通过<input type="file">选中了一个或多个文件时,这些文件就存储在这个文件列表中。- 文件列表是一个类数组对象,可以根据其
.length来得知用户选择了多少个文件 - 文件列表可以通过索引访问`fileInput.files[0]
- 因为文件列表是一个类数组对象,所以可以很轻易地转成真正的数组对象。
Array.form(fileInput.files)。以便forEach,map,filter等方法 - 还可以通过
for...of来遍历
for (const file of fileInput.files) {
console.log(file.name);
}
"file"是服务器端用来识别这个数据的键(key) 或字段名。例如:在Django中通过request.FILES['file']来获取文件
9 封装实用函数
async function fetchData(url, method = 'GET', data = null) {
const config = {
method,
headers: { 'Content-Type': 'application/json' }
};
if (data) config.body = JSON.stringify(data);
try {
const response = await fetch(url, config);
if (!response.ok) throw new Error(`HTTP error! ${response.status}`);
return await response.json();
} catch (error) {
console.error('请求失败:', error);
throw error;
}
}
10 注意事项
- 默认不发送cookies,需设置
credentials: 'include' - 跨域请求需要服务器支持CORS
- HTTP错误状态(如404)不会自动触发catch
- 考虑添加请求超时处理
11 补充:csrf验证
// 获取csrfToken
const csrfToken = getCookie('csrftoken');
fetch(url,{
method:'POST',
body:user_body,
// 把csrfToken加到请求头里
headers:{
'X-CSRFToken': csrftoken
}
})
// 获取cookie
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.startsWith(name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
12 补充:后端返回204时可供复制的代码
.then(response =>{
if(response.status === 204){
return null; // 返回null不做处理
}
// 检测返回值类型是否为json
const contentType = response.headers.get('content-type');
if(!contentType?.includes('application/json')){
return null;//非json响应
}
// json解析失败返回null
return response.json().catch(() => null);
})
.then(data => {
if(data !== null){
console.log("接收到数据:",data);
}else{
console.log("已发送验证码,但无数据返回(204)")
}
})
.catch(error => {
console.log("请求发送错误:",error);
})
13 补充:.json .text()等fetch方法返回Promise对象情况说明
14 补充:async/await 与 Promise.then() 语法对比
async/await 与 Promise.then() 语法对比
15 补充:读取response响应体的几种类型
- response.text() 把响应体当字符串读出
- response.json() 把响应体解析成json对象
- response.blob() 把响应体当做文件(二进制)读出
16 补充:构造新文件/修改文件名
File对象的name属性是只读的,无法直接做出修改。但是可以通过构造新文件的方法来实现修改文件名
如果你要上传时使用新名字,需要 重新构造一个 File 对象,然后把它 append 到 FormData
构造新文件:new File([原文件], 新文件名, {type:原文件类型})
Array.from(fileInput.files).forEach((file, index) => {
const newName = rename_list[index] || file.name; // 如果没提供新名字,就用原名
const newFile = new File([file], newName, { type: file.type });
const formData = new FormData();
formData.append("file", newFile);
console.log("filename:", newFile.name);
fetch(upload_url, {
method: "POST",
body: formData,
headers: {
"X-CSRFToken": csrfToken
}
});
});
重要提醒:任何时候看到 .json()、.text() 等 fetch 相关方法,都要使用 await 来获取实际数据!
58 JavaScript 可选链操作符 ?. 详解
基本概念
可选链操作符 ?. 是 ES2020 引入的特性,用于安全地访问嵌套对象属性或调用可能不存在的方法。
核心作用
- 安全访问可能为
null或undefined的属性/方法 - 避免抛出
TypeError - 使代码更简洁
典型用法
1. 安全访问属性
const street = user?.address?.street;
如果 address 为 null,返回 undefined 而不是报错
2. 安全调用方法
if (!contentType?.includes('application/json')) {
return null;
}
3. 安全访问数组元素
const firstItem = arr?.[0];
与传统写法的对比
| 可选链写法 | 传统等价写法 |
|---|---|
obj?.prop |
obj && obj.prop |
obj?.[expr] |
obj && obj[expr] |
obj?.method() |
obj && obj.method() |
浏览器兼容性
- Chrome 80+
- Firefox 74+
- Safari 13.1+
- Node.js 14.0+
旧环境需要通过 Babel 转译
注意事项
- 不能用于赋值操作
- 不能替代必要的空值检查
- 过度使用可能掩盖潜在问题
实际应用场景
- API 响应处理
- 配置对象访问
- 动态内容处理
59 页面重定向
| 方法 | 是否新增历史记录 | 是否刷新页面 | 适用场景 |
|---|---|---|---|
window.location.href |
✅ 是 | ✅ 是 | 通用跳转 |
window.location.replace() |
❌ 否 | ✅ 是 | 不希望用户返回 |
window.open() |
- | ❌ 否 | 新标签页打开 |
<meta refresh> |
✅ 是 | ✅ 是 | HTML自动跳转 |
history.pushState() |
✅ 是 | ❌ 否 | SPA前端路由(可返回) |
history.replaceState() |
❌ 否 | ❌ 否 | SPA修改URL(不可返回) |
| 表单提交跳转 | ✅ 是 | ✅ 是 | 提交表单数据后跳转 |
60 JavaScript中可供监听的条件
一、DOM 相关事件
1. 文档/窗口事件
DOMContentLoaded - HTML文档完全加载和解析完成
load - 所有资源加载完成
beforeunload - 窗口/文档即将卸载
unload - 窗口/文档正在卸载
error - 资源加载失败
abort - 资源加载中止
2. 鼠标事件
click - 点击(按下并释放)
dblclick - 双击
mousedown - 鼠标按钮按下
mouseup - 鼠标按钮释放
mousemove - 鼠标移动
mouseover - 鼠标移入元素
mouseout - 鼠标移出元素
mouseenter - 鼠标进入元素(不冒泡)
mouseleave - 鼠标离开元素(不冒泡)
contextmenu - 右键菜单
3. 键盘事件
keydown - 按键按下
keyup - 按键释放
keypress - 按键按下并产生字符(已废弃)
4. 表单事件
submit - 表单提交
reset - 表单重置
change - 表单元素值改变
input - 输入值变化(实时)
focus - 元素获得焦点
blur - 元素失去焦点
select - 文本被选中
二、浏览器/页面事件
1. 视图事件
resize - 窗口大小改变
scroll - 滚动事件
fullscreenchange - 全屏状态改变
hashchange - URL哈希改变
2. 剪贴板事件
copy - 复制操作
cut - 剪切操作
paste - 粘贴操作
三、多媒体事件
1. 视频/音频事件
play - 媒体开始播放
pause - 媒体暂停
ended - 媒体播放结束
timeupdate - 播放位置改变
volumechange - 音量改变
ratechange - 播放速度改变
2. 图片事件
load - 图片加载完成
error - 图片加载失败
四、设备相关事件
1. 触摸事件
touchstart - 触摸开始
touchmove - 触摸移动
touchend - 触摸结束
touchcancel - 触摸中断
2. 传感器事件
deviceorientation - 设备方向改变
devicemotion - 设备加速度变化
3. 网络状态
online - 网络连接恢复
offline - 网络断开
五、CSS和动画事件
1. 过渡事件
transitionstart - CSS过渡开始
transitionend - CSS过渡结束
transitioncancel - CSS过渡取消
2. 动画事件
animationstart - CSS动画开始
animationend - CSS动画结束
animationiteration - CSS动画重复播放
六、特殊事件
1. 拖放事件
drag - 元素被拖动
dragstart - 拖动开始
dragend - 拖动结束
dragenter - 拖动进入目标
dragleave - 拖动离开目标
dragover - 拖动在目标上移动
drop - 拖动释放
2. WebSocket事件
open - 连接建立
message - 收到消息
error - 连接错误
close - 连接关闭
七、自定义事件
// 创建
const event = new CustomEvent('myEvent', { detail: { key: 'value' } });
// 触发
element.dispatchEvent(event);
// 监听
element.addEventListener('myEvent', handler);
监听方法通用语法
element.addEventListener('事件类型', function(event) {
// 事件处理逻辑
// event对象包含事件相关信息
}, useCapture);
注意事项
- 某些事件在不同浏览器中可能有兼容性问题
- 移动端和桌面端支持的事件可能有差异
- 频繁触发的事件需要节流或防抖
- 移除不需要的事件监听器避免内存泄漏
61 this在箭头函数与普通函数中的区别
普通函数中的this
在你的原始代码中,如果使用普通函数(如 function() {...}),this 会指向调用该函数的对象,也就是被点击的 DOM 元素:
changeButton.addEventListener("click", function() {
// 这里的 this 指向被点击的元素(changeButton)
console.log(this); // 输出 <span class="function">...</span>
this.classList.add("active"); // 可以正常工作
});
箭头函数中的 this
箭头函数 (() => {...}) 没有自己的 this,它会继承外层作用域的 this:
changeButton.addEventListener("click", () => {
// 这里的 this 不是指向被点击的元素!
console.log(this); // 可能输出 window 对象或其他外层 this
this.classList.add("active"); // 会报错,因为 this 不是 DOM 元素
});
62 处理js灵异现象
1. 当你的js代码莫名失效时/不,请无论写什么js代码都加上,总不会错的
// 等待DOM节点全部加载后再载入js代码
document.addEventListener("DOMContentLoaded",function(){}
2. 如果第一招不行,请尝试第二招:按Ctrl+F5强制刷新清除缓存
63 JavaScript中关于事件的方法
核心方法
1. preventDefault()
作用:阻止事件的默认行为。
说明:仅当事件的 cancelable 属性为 true 时有效。
示例代码:
// 阻止链接跳转
document.getElementById('myLink').addEventListener('click', function(e) {
e.preventDefault();
console.log('链接点击被阻止');
});
// 阻止表单提交
document.getElementById('myForm').addEventListener('submit', function(e) {
if (!validateForm()) {
e.preventDefault();
alert('表单验证失败!');
}
});
适用事件:submit, click(在链接上), contextmenu 等。
2. stopPropagation()
作用:立即停止事件在 DOM 层次中的传播,阻止事件冒泡或捕获。
说明:阻止事件向上(冒泡阶段)或向下(捕获阶段)传递,但当前节点上的其他同类事件监听器仍会执行。
示例代码:
document.getElementById('inner').addEventListener('click', function(e) {
e.stopPropagation();
console.log('事件冒泡被阻止,父元素不会收到点击事件');
});
适用事件:所有冒泡的事件。
3. stopImmediatePropagation()
作用:立即停止事件传播,并阻止当前元素上任何后续的同类事件监听器被执行。
说明:比 stopPropagation() 更强大,会阻止当前元素上所有后续的事件监听器。
示例代码:
element.addEventListener('click', function(e) {
e.stopImmediatePropagation();
console.log('这是唯一会执行的点击监听器');
});
element.addEventListener('click', function() {
console.log('这个监听器不会被执行');
});
适用事件:所有冒泡的事件。
4. composedPath()
作用:返回一个数组,包含事件触发后所经过的所有节点(事件传播路径)。
说明:在 Web Components 和 Shadow DOM 中特别有用。
示例代码:
element.addEventListener('click', function(e) {
const path = e.composedPath();
console.log('事件传播路径:', path);
});
常用事件属性
虽然这些是属性而非方法,但对理解事件处理至关重要:
| 属性 | 描述 | 示例 |
|---|---|---|
target |
真正触发事件的最内层元素 | 点击按钮,e.target 就是按钮元素 |
currentTarget |
附加事件处理程序的当前元素 | 等同于 this |
type |
事件的类型(字符串) | 'click', 'submit', 'keydown' |
eventPhase |
事件当前阶段:1-捕获,2-目标,3-冒泡 |
|
bubbles |
布尔值,表示事件是否冒泡 | submit 不冒泡,click 冒泡 |
cancelable |
布尔值,表示默认行为是否可被阻止 | |
clientX / clientY |
鼠标相对于浏览器视口的坐标 | |
pageX / pageY |
鼠标相对于整个文档的坐标(含滚动偏移) | |
key |
键盘事件中按下的键的字符串值 | 'a', 'Enter', 'ArrowUp' |
总结表格
| 方法 | 核心目的 | 使用场景 |
|---|---|---|
preventDefault() |
取消浏览器默认行为 | 阻止表单提交、链接跳转等 |
stopPropagation() |
阻止事件继续传播 | 防止事件触发父元素处理程序 |
stopImmediatePropagation() |
更强力地阻止,包括当前元素的其他监听器 | 事件处理需要独占时 |
composedPath() |
获取事件的传播路径 | 调试或处理 Shadow DOM 事件 |
最佳实践建议:谨慎使用 stopPropagation(),因为它可能会干扰其他代码或第三方库对事件的正常监听。
64 Promise 解析详解
promise! --ctrf+f跳转用
什么是 Promise?
Promise 是 JavaScript 中处理异步操作的对象。它代表一个尚未完成但预期会在未来完成的操作(或失败)的结果。
Promise 的三种状态
- pending(等待中):初始状态,既不是成功,也不是失败
- fulfilled(已成功):操作成功完成
- rejected(已失败):操作失败
代码中的问题分析
const data = response.json(); // 这里返回的是 Promise 对象
console.log(data.redirict); // 这里访问的是 Promise 对象,不是实际数据
response.json() 返回的是一个 Promise,不是直接的数据!
Promise 解析的三种方式
方式一:使用 async/await(推荐)
async function handleResponse() {
try {
const response = await fetch('your-url');
const data = await response.json(); // 等待 Promise 解析
console.log(data.redirict); // 现在可以访问真实数据
} catch (error) {
console.error('错误:', error);
}
}
方式二:使用 .then() 链式调用
fetch('your-url')
.then(response => response.json()) // 返回新的 Promise
.then(data => { // 等待上一个 Promise 解析
console.log(data.redirict); // 访问解析后的数据
})
.catch(error => {
console.error('错误:', error);
});
方式三:使用 Promise 构造函数
new Promise((resolve, reject) => {
fetch('your-url')
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
})
.then(data => {
console.log(data.redirict);
})
.catch(error => {
console.error('错误:', error);
});
实际例子对比
错误的方式
const response = await fetch('/api/login');
const dataPromise = response.json(); // 这是 Promise 对象
console.log(dataPromise); // 输出: Promise {<pending>}
console.log(dataPromise.redirict); // 输出: undefined
正确的方式
const response = await fetch('/api/login');
const data = await response.json(); // 等待 Promise 解析
console.log(data); // 输出: {redirict: "/index/", ...}
console.log(data.redirict); // 输出: "/index/"
Promise 的工作原理
// 模拟 response.json() 的工作原理
function模拟的Json解析() {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟异步解析 JSON
const data = { redirict: "/index/", user: "张三" };
resolve(data); // 解析完成,传递数据
}, 100);
});
}
// 使用
async function 示例() {
const promise对象 = 模拟的Json解析(); // 获取 Promise
console.log(promise对象); // Promise {<pending>}
const 真实数据 = await promise对象; // 等待解析
console.log(真实数据.redirict); // "/index/"
}
为什么需要 await?
- 异步操作:JSON 解析可能需要时间(特别是大文件)
- 非阻塞:JavaScript 是单线程的,await 让代码"等待"而不阻塞其他操作
- 错误处理:可以配合 try-catch 进行优雅的错误处理
常见误区
// 错误:忘记 await
const data = response.json();
console.log(data); // Promise对象,不是数据
// 错误:在 async 函数外使用 await
function regularFunction() {
const data = await response.json(); // 语法错误
}
// 正确:在 async 函数中使用
async function correctFunction() {
const data = await response.json(); // 正确
}
总结
- Promise 是容器:它包裹着未来会有的值
- 需要解析:使用
await或.then()来获取实际值 - 错误处理:使用
try-catch或.catch()处理可能的错误 - async/await 更清晰:让异步代码看起来像同步代码,更易读
重要提醒:任何时候看到 .json()、.text() 等 fetch 相关方法,都要使用 await 来获取实际数据!
65 async/await 与 Promise.then() 语法对比
概述
async/await 和 Promise.then() 都是 JavaScript 中处理异步操作的方法,但它们在语法结构、可读性和使用方式上有重要区别。
语法结构对比
async只需要在await所属的函数前做标记即可
async/await 写法
async function fetchData() {
try {
const response = await fetch('/api/data/');
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.error('Error:', error);
}
}
.then() 写法
function fetchData() {
return fetch('/api/data/')
.then(response => response.json())
.then(data => {
console.log(data);
return data;
})
.catch(error => {
console.error('Error:', error);
});
}
主要区别对比
| 特性 | async/await | .then() |
|---|---|---|
| 代码可读性 | 更像同步代码,易于理解 | 回调嵌套,可读性较差 |
| 错误处理 | 使用 try-catch,更直观 | 使用 .catch() 方法 |
| 调试体验 | 堆栈跟踪更清晰 | 堆栈跟踪可能不完整 |
| 变量作用域 | 变量在同一个作用域内 | 每个 then() 有独立作用域 |
| 流程控制 | 可以使用 for 循环、if 语句等 | 需要链式调用 |
实际应用场景
多个异步操作顺序执行
async/await:
async function processUserData() {
try {
const user = await fetchUser();
const profile = await fetchProfile(user.id);
const posts = await fetchPosts(user.id);
return { user, profile, posts };
} catch (error) {
console.error('Process failed:', error);
}
}
.then():
function processUserData() {
return fetchUser()
.then(user => fetchProfile(user.id))
.then(profile => fetchPosts(profile.userId))
.then(posts => {
return { user: posts.user, profile: posts.profile, posts };
})
.catch(error => {
console.error('Process failed:', error);
});
}
并行异步操作
async/await:
async function fetchAllData() {
try {
const [userData, productData, orderData] = await Promise.all([
fetch('/api/user/'),
fetch('/api/products/'),
fetch('/api/orders/')
]);
return {
user: await userData.json(),
products: await productData.json(),
orders: await orderData.json()
};
} catch (error) {
console.error('Fetch failed:', error);
}
}
.then():
function fetchAllData() {
return Promise.all([
fetch('/api/user/').then(r => r.json()),
fetch('/api/products/').then(r => r.json()),
fetch('/api/orders/').then(r => r.json())
])
.then(([user, products, orders]) => {
return { user, products, orders };
})
.catch(error => {
console.error('Fetch failed:', error);
});
}
错误处理对比
async/await 错误处理:
async function getUser() {
try {
const response = await fetch('/api/user/');
if (!response.ok) {
throw new Error('Network response was not ok');
}
return await response.json();
} catch (error) {
console.error('Failed to fetch user:', error);
}
}
.then() 错误处理:
function getUser() {
return fetch('/api/user/')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.catch(error => {
console.error('Failed to fetch user:', error);
});
}
选择建议
使用 async/await 当:
- 代码需要顺序执行多个异步操作
- 需要更好的可读性和维护性
- 需要进行复杂的错误处理
- 需要像写同步代码一样写异步代码
使用 .then() 当:
- 处理简单的 Promise 链
- 需要向后兼容旧的 JavaScript 环境
- 进行简单的转换或过滤操作
现代开发推荐
推荐使用 async/await,因为它:
- 代码更简洁易读
- 错误处理更直观
- 调试更方便
- 是现代 JavaScript 的标准写法
async function handleDjangoRedirect() {
try {
const response = await fetch('/api/endpoint/');
const data = await response.json();
if (data.redirect) {
window.location.href = data.redirect;
}
} catch (error) {
console.error('Request failed:', error);
}
}
总结
两者在功能上是等价的,但 async/await 提供了更好的开发体验和代码质量,是现代 JavaScript 开发的首选方式。
66 JavaScript 函数传递:直接调用 vs 函数引用
本质区别
1. 直接调用:logout(exit_url)
exit_button.addEventListener("click", logout(exit_url))
执行过程:
- JavaScript 引擎遇到
logout(exit_url)时立即执行该函数 - 执行函数并等待其完成(因为是 async 函数,返回 Promise)
- 将函数的返回值(Promise 对象)作为第二个参数传递给
addEventListener - 事件触发时尝试调用这个 Promise 对象,但 Promise 对象不是函数,所以无效
相当于:
const result = logout(exit_url); // 立即执行,返回 Promise
exit_button.addEventListener("click", result); // 传递 Promise,无效
2. 函数引用:() => logout(exit_url)
exit_button.addEventListener("click", () => logout(exit_url))
执行过程:
- 创建一个箭头函数(匿名函数)
- 将这个函数对象作为第二个参数传递给
addEventListener - 只有当点击事件发生时,才会执行这个箭头函数
- 箭头函数内部再调用
logout(exit_url)
相当于:
const clickHandler = () => {
return logout(exit_url);
};
exit_button.addEventListener("click", clickHandler); // 传递函数,有效
详细对比
| 特性 | logout(exit_url) |
() => logout(exit_url) |
|---|---|---|
| 执行时机 | 代码解析时立即执行 | 点击事件发生时执行 |
| 传递的内容 | 函数的返回值(Promise) | 函数对象本身 |
| 事件处理 | 无效(传递的不是函数) | 有效(传递的是函数) |
| 参数传递 | 立即传递参数 | 通过闭包捕获参数 |
| 内存使用 | 立即执行,无额外内存 | 创建函数对象,占用内存 |
技术原理
立即调用的技术细节
// 代码执行顺序:
// 1. 解析 logout(exit_url) → 立即执行函数
// 2. 执行异步操作 → 发送网络请求
// 3. 返回 Promise 对象
// 4. 将 Promise 传递给 addEventListener
// 5. 点击事件发生时:Promise() → 无效调用
函数引用的技术细节
// 代码执行顺序:
// 1. 创建箭头函数对象(不立即执行)
// 2. 将函数对象传递给 addEventListener
// 3. 用户点击按钮
// 4. 浏览器调用箭头函数
// 5. 箭头函数内部调用 logout(exit_url)
实际示例
错误示例的调试
console.log('开始执行脚本'); // 1. 最先输出
exit_button.addEventListener("click", logout(exit_url));
async function logout(url) {
console.log('logout函数被调用'); // 2. 立即输出,而不是点击时输出
const response = await fetch(url);
// ... 其他代码
}
console.log('脚本执行结束'); // 3. 最后输出(可能在网络请求之后)
正确示例的调试
console.log('开始执行脚本'); // 1. 输出
exit_button.addEventListener("click", () => {
console.log('点击事件发生'); // 只在点击时输出
logout(exit_url);
});
async function logout(url) {
console.log('logout函数被调用'); // 只在点击时输出
const response = await fetch(url);
// ... 其他代码
}
console.log('脚本执行结束'); // 2. 输出
67.关于Blob二进制容器的介绍
blob!
简介
在前端里,blob 是 Binary Large Object 的缩写,本质上就是一段二进制数据的容器。
Blob对象 可以表示文件数据、图片、视频、音频、压缩包等等二进制内容。- 它可以看作是“内存里的临时文件”。
- 浏览器无法直接把
fetch得到的二进制流保存成文件,所以需要先转成Blob,然后再交给<a>标签下载。
68.for-each用法
基本语法
array.forEach(function(element, index, array) {
// 在这里写对每个元素要执行的操作
});
参数说明:
element:当前元素index:当前元素的索引array:正在遍历的整个数组
示例:
let fruits = ["apple", "banana", "cherry"];
// 遍历数组并打印
fruits.forEach(function(item, index) {
console.log(index + ": " + item);
});
运行结果:
0: apple
1: banana
2: cherry
⚠️ 注意:
forEach 不能中途 break 或 return 来终止循环,如果需要中途退出,可以考虑用 for...of 或 some / every。
69.匿名函数
直接调用匿名函数
(function(a)) {
console.log(a);
})(123);
还可以把变量设成函数,调用 fn() 即调用了匿名函数的功能
var fn = function() {
return "将匿名函数赋值给变量"
}
70.回调函数
把函数当作参数交给别人,让别人在合适时机调用
function doSomething(cb) {
console.log("做一些事情");
cb(); // 在合适时机调用回调
}
doSomething(() => {
console.log("回调被触发");
});

浙公网安备 33010602011771号