先观察以下代码,思考输出结果:
javascript 体验AI代码助手 代码解读复制代码function f() {
for(var i = 0; i < 10; i++) {
setTimeout(() => {
console.log('i=', i)
});
}
}
f();输出结果:
ini 体验AI代码助手 代码解读复制代码i= 10
i= 10
i= 10
...(共 10 次)css 体验AI代码助手 代码解读复制代码for(var i = 0; i < 10; i())
↑
└── var 声明的变量是函数作用域
整个函数 f 内都能访问这个 imarkdown 体验AI代码助手 代码解读复制代码循环次数 i 的值 循环条件 (i < 10)
---------------------------------------
第 1 次 0 ✓ 通过
第 2 次 1 ✓ 通过
...
第 10 次 9 ✓ 通过
10 ✗ 不通过,循环结束
循环结束后:i = 10css 体验AI代码助手 代码解读复制代码for(var i = 0; i < 10; i++) {
setTimeout(() => {
console.log('i=', i) // ← 所有回调共享同一个 i
});
}每次循环创建一个箭头函数,都通过闭包引用变量 i
css 体验AI代码助手 代码解读复制代码时间轴:
─────────────────────────────────────────
| 同步执行阶段 | 异步执行阶段 |
─────────────────────────────────────────
for 循环完成 setTimeout 回调执行
i 递增到 10 读取 i 的值(此时 i=10)
输出 10 次 i=10
─────────────────────────────────────────less 体验AI代码助手 代码解读复制代码变量 i 的生命周期:
─────────────────────────────→ 时间
0 1 2 3 4 5 6 7 8 9 10
└───┬───┘ └───┬───┘
│ │
同步循环执行 循环结束
i=10
回调函数 1: ────────────────────→ 读取 i (10)
回调函数 2: ────────────────────→ 读取 i (10)
...
回调函数 10: ────────────────────→ 读取 i (10)javascript 体验AI代码助手 代码解读复制代码function f() {
for(let i = 0; i < 10; i++) {
setTimeout(() => {
console.log('i=', i)
});
}
}原理: let 是块级作用域,每次循环创建新的 i 绑定
输出: i= 0 到 i= 9 各一次
javascript 体验AI代码助手 代码解读复制代码function f() {
for(var i = 0; i < 10; i++) {
(function(j) {
setTimeout(() => {
console.log('i=', j)
});
})(i);
}
}原理: 通过函数参数保存每次循环的 i 值
javascript 体验AI代码助手 代码解读复制代码function f() {
for(var i = 0; i < 10; i++) {
setTimeout((j) => {
console.log('i=', j)
}, 0, i);
}
}原理: setTimeout 的第三个参数会传递给回调函数
概念 | 说明 |
|---|---|
var 作用域 | 函数作用域,非块级作用域 |
let 作用域 | 块级作用域,每次循环创建新绑定 |
闭包 | 函数可以访问其声明时所在作用域的变量 |
异步 | setTimeout 的回调会延迟执行 |
共享引用 | 同一作用域的闭包引用同一个变量 |
var 的函数作用域 + 闭包共享变量 + setTimeout 异步执行 = 所有回调读取到循环结束后的同一个 i 值(10)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。