带有循环的奇怪闭包行为
Weird closure behavior with loop
所以我已经在 SO 上学到了很多关于闭包的知识。
但我仍然发现了一个我无法向自己解释的例子:
function buildList(list){
var result = [];
for(var i = 0; i < list.length; i++) {
var item = "item: " + list[i] + " i's value: " + i; //i has the value of 2 here, but why?
result.push( function(){document.write(item + ", list[i]:" + list[i] + ", i's value in the anonymous function:" + i + "<br>")});
} //i = 3 here
return result;
}
function testList(){
var testTheList = buildList([1,2,3]);
for (var j = 0; j < testTheList.length; j++) {
testTheList[j]();
}
}
testList();
正如我对闭包的预期,当我执行 testList() 时,我应该是 3。
但结果是:
item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3
item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3
item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3
为什么 is i 对于 var item => 2 而 i 在匿名函数中 => 3 ?正如我所读,闭包创建了新的执行环境,但我不应该为闭包设置相同的值吗?
编辑
这不是 JavaScript closure inside loops – simple practical example 的副本,我不想知道如何创建新的执行环境。
我想知道为什么(循环的)相同变量 i 的值在相同范围内不同?
当您将新函数添加到 result
列表时,它会引用 item
变量和 i
计数器。在 buildList
函数内的循环期间,您并没有创建几个 item
变量,而是在 buildList
函数执行结束时覆盖现有变量 item
和 i
变量看起来像这样:
- 3
- "item: 3 i's value: 2"
而 list[i]
是 undefined
因为你的列表长度是 3,你没有 list[3]
项目。因此,当您从 testList
中的循环调用匿名函数时,它会重新运行您与 item
和 i
变量保留的完全相同的值。同时在循环中创建匿名函数这不是最佳实践,我建议您像这样修改 buildList
函数:
function buildList(list) {
var index = 0;
return function () {
if (index >= list.length) return
var item = "item: " + list[index] + " i's value: " + index;
document.body.innerHTML += [
item, ", list[i]:", list[index],
", i's value in the anonymous function:",
index, "<br>"
].join('')
index++
}
}
function testList() {
var list = [1, 2, 3];
var testTheList = buildList(list);
document.body.innerHTML = '';
for (var j = 0; j < list.length; j++) {
testTheList();
}
}
testList();
所以我已经在 SO 上学到了很多关于闭包的知识。
但我仍然发现了一个我无法向自己解释的例子:
function buildList(list){
var result = [];
for(var i = 0; i < list.length; i++) {
var item = "item: " + list[i] + " i's value: " + i; //i has the value of 2 here, but why?
result.push( function(){document.write(item + ", list[i]:" + list[i] + ", i's value in the anonymous function:" + i + "<br>")});
} //i = 3 here
return result;
}
function testList(){
var testTheList = buildList([1,2,3]);
for (var j = 0; j < testTheList.length; j++) {
testTheList[j]();
}
}
testList();
正如我对闭包的预期,当我执行 testList() 时,我应该是 3。
但结果是:
item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3
item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3
item: 3 i's value: 2, list[i]:undefined, i's value in the anonymous function:3
为什么 is i 对于 var item => 2 而 i 在匿名函数中 => 3 ?正如我所读,闭包创建了新的执行环境,但我不应该为闭包设置相同的值吗?
编辑
这不是 JavaScript closure inside loops – simple practical example 的副本,我不想知道如何创建新的执行环境。
我想知道为什么(循环的)相同变量 i 的值在相同范围内不同?
当您将新函数添加到 result
列表时,它会引用 item
变量和 i
计数器。在 buildList
函数内的循环期间,您并没有创建几个 item
变量,而是在 buildList
函数执行结束时覆盖现有变量 item
和 i
变量看起来像这样:
- 3
- "item: 3 i's value: 2"
而 list[i]
是 undefined
因为你的列表长度是 3,你没有 list[3]
项目。因此,当您从 testList
中的循环调用匿名函数时,它会重新运行您与 item
和 i
变量保留的完全相同的值。同时在循环中创建匿名函数这不是最佳实践,我建议您像这样修改 buildList
函数:
function buildList(list) {
var index = 0;
return function () {
if (index >= list.length) return
var item = "item: " + list[index] + " i's value: " + index;
document.body.innerHTML += [
item, ", list[i]:", list[index],
", i's value in the anonymous function:",
index, "<br>"
].join('')
index++
}
}
function testList() {
var list = [1, 2, 3];
var testTheList = buildList(list);
document.body.innerHTML = '';
for (var j = 0; j < list.length; j++) {
testTheList();
}
}
testList();