我正在阅读一篇文章(JavaScript Closures for Dummies),其中一个例子如下。
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
调用testList时,会出现一个警告框,其中显示“item3 undefined”。文章有这样的解释:
当在行
fnlist[j]();
上调用匿名函数时,它们都使用相同的单个闭包,并且它们在该闭包中使用i和item的当前值(其中我的值为3,因为循环已完成,项目的值为“item3”。
为什么item的值为'item3'?当我变成3时,for循环结束了吗?如果它结束应该不是项目仍然是'item2'?或者当testList调用函数时,是否再次创建变量项?
答案 0 :(得分:4)
你很亲密......
为什么item的值为'item3'?当我变成3时,for循环结束了吗?
是
如果它结束应该不是项目 'ITEM2'?
不。这个例子有点棘手。在循环的最后一次迭代期间,i
为2,但它引用list
数组的第3个元素,即3。换句话说,item == 'item' + list[2] == 'item3'
或者当testList调用函数时,是否再次创建变量项?
不,你第一次几乎是对的。我想你错过了item[2]
的值为3。
答案 1 :(得分:4)
在执行以下操作之前,buildList中的for循环完成:
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
...因此,到那时(当你调用每个函数时),变量item
将是最后分配给它的任何东西(即“item3”),而i
将是{ {1}}(作为上次3
操作的结果),i++
为list[3]
。
这与循环在调用 closure'd 函数之前完成的事实有关。为了防止这种情况,您可以创建一个新的闭包,如下所示:
undefined
答案 2 :(得分:2)
如你所说,list
变量存储在闭包中。
实际上您可以访问list
变量,但是您尝试访问list[3]
。毕竟,i
变量也存储为闭包,调用console.log
函数时它的值为3。
答案 3 :(得分:2)
我认为您遗漏的一点是list[i]
未定义,因为i
为3,而list
仅定义为0..2。
答案 4 :(得分:0)
当我变为3时循环结束,但是存储在闭包中并通过alert显示的“item”变量设置为
var item = 'item' + list[i];
文本'item'+列表中的值[2]。第三个列表项是3,因此文本是item3