我正在努力关闭,我知道在循环中,新函数使用迭代器的最后一个值引用闭包
所以以下函数的结果是三次“item3 undefined”
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]();
}
}
然后我知道匿名函数可以引出范围,所以我将第一个函数编辑为:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
(function(){
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
})();
}
return result;
}
但结果是“item1 undefined”,“item2 undefined”,“item3 undefined”,
所以我的问题是,在使用范围后,为什么结果仍然未定义?
答案 0 :(得分:0)
您应该将i传递给匿名函数:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
(function(i){
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
})(i);
}
return result;
}
答案 1 :(得分:0)
i
仍然引用绑定到父作用域的变量,而不是FunctionExpression引入的变量。
正确的解决方法是将新变量绑定到新范围
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
(function(i){
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
})(i);
}
return result;
}
注意传递给函数的i
。
答案 2 :(得分:0)
假设此代码的目的只是为了学习;你创建一个匿名函数,但你仍然指的是前一个范围中的i
,所以你不要改变你最初编写的第一个代码; i
仍然具有最后一个值(list.length
)。
为了避免这种情况,您需要在您创建的函数范围内具有i
的当前值:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push(function (index) {
return function() {alert(item + ' ' + list[index])}
}(i));
}
return result;
}
或者,您可以使用bind进行部分申请:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push(function(index) {alert(item + ' ' + list[index])}.bind(null, i))
}
return result;
}
在ES6或启用了JS 1.8.5的Firefox中,您还可以使用声明块范围变量的let:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
let index = i;
result.push(() =>alert(item + ' ' + list[index]));
}
return result;
}
在最后一个示例中,还有ES6 arrow functions。