闭包
🛠 代码解析
function createFunctions() {
let funcs = [];
for (var i = 0; i < 3; i++) { // `i` 用 var 声明,属于 `createFunctions` 作用域
funcs.push(() => console.log(i)); // 闭包捕获 `i`
}
return funcs;
}
const myFuncs = createFunctions();
myFuncs[0](); // 3
myFuncs[1](); // 3
myFuncs[2](); // 3
🔹 为什么 myFuncs[0]()
、myFuncs[1]()
、myFuncs[2]()
都输出 3
?
var i
作用域属于createFunctions()
函数,不是for
循环的局部变量。funcs.push(() => console.log(i));
这个箭头函数不会立即执行,而是把 对i
的引用 存入funcs
数组。for
循环结束后,i = 3
(因为i++
使i === 3
时跳出循环)。- 当
myFuncs[0]()
、myFuncs[1]()
、myFuncs[2]()
执行时,它们都访问的是同一个i
,此时i = 3
,所以它们都打印3
。
🔬 如何修正?
✅ 解决方案 1:使用 let
(块级作用域)
function createFunctions() {
let funcs = [];
for (let i = 0; i < 3; i++) { // `let i` 作用域在 `{}` 内,每次循环都是新的 `i`
funcs.push(() => console.log(i));
}
return funcs;
}
const myFuncs = createFunctions();
myFuncs[0](); // 0
myFuncs[1](); // 1
myFuncs[2](); // 2
💡 let
具有块级作用域,每次循环 i
都是一个新的变量(不同作用域),所以 funcs[i]
绑定的是各自的 i
值。
✅ 解决方案 2:使用 IIFE
(立即执行函数表达式)
function createFunctions() {
let funcs = [];
for (var i = 0; i < 3; i++) {
(function(i) { // 立即执行函数创建一个新的作用域,i 作为参数传入
funcs.push(() => console.log(i));
})(i);
}
return funcs;
}
const myFuncs = createFunctions();
myFuncs[0](); // 0
myFuncs[1](); // 1
myFuncs[2](); // 2
💡 IIFE
(立即执行函数表达式)创建了一个新的作用域,使 i
变成局部变量,因此每次循环 funcs.push(() => console.log(i));
绑定的都是不同的 i
值。