如何在闭包中引用局部变量?

时间:2009-06-01 02:15:24

标签: javascript loops closures

我正在阅读一篇文章(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调用函数时,是否再次创建变量项?

5 个答案:

答案 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