我试图理解 JavaScript 中的闭包,并遇到了这个例子:
for (let i = 0; i < 3; i++) {
const log = () => {
console.log(i);
};
setTimeout(log, 100);
}
由于变量
i
的作用域为 for
循环,因此在每次迭代中都会给它一个新的引用,因此它不会在迭代之间共享,因此闭包捕获 log
函数以及对每次迭代中的 i
变量。
正如预期的输出是:
$ 0
$ 1
$ 2
但是,在以下代码片段中,行为有所不同:
for (let arr = [1, 2, 3]; arr.length !== 0; arr.pop()) {
const log = () => {
console.log(arr);
};
setTimeout(log, 1000);
}
预期输出是
$ [1, 2, 3]
$ [1, 2]
$ [1]
但是我得到了 3 个带有空数组的日志,这表明
arr
变量可能在迭代之间共享。
不同之处在于,i 是一个整数,作为复制参数传递给另一个函数。 arr 是作为参考参数传递的数组。
所以超时后,即使原始值改变了,副本也没有改变,但引用的却改变了。
您的
arr
变量在循环的每次迭代中都会初始化为数组的 reference。它确实在每次迭代中都是一个不同的变量,但只有一个数组,并且您的循环在每次迭代时都会弹出一个值。因此,当计时器触发时,数组已空。
for
循环中的局部作用域变量如何工作的精确细节有点复杂。初始化表达式计算一次(我很确定;规范很难阅读),然后在每次迭代时创建一个新变量并将其初始化为前一个变量的值。因此,在数组引用的情况下,变量的直接值不会改变。如果您可以以某种方式执行“last_variable === this_variable”测试(您不能),那么迭代之间将是true
,因为它是相同的数组。但如果是原始值,那就不一样了。