修复此Javascript闭包的正确方法是什么?

时间:2011-11-22 17:14:45

标签: javascript closures

我一直在熟悉javascript闭包并浏览了这篇文章 http://blog.morrisjohns.com/javascript_closures_for_dummies.html

由于关闭,示例5不能按预期工作。如何修改

result.push( function() {alert(item + ' ' + list[i])} );

使代码有效?

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();

谢谢!

4 个答案:

答案 0 :(得分:6)

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 :(得分:3)

您需要来自不同函数的iitem作为不同范围内的单独变量(因此它们可以具有不同的值而不是共享)。由于Javascript只有函数作用域,因此需要创建一个包含这些变量的包装函数

function buildList(list) { 
  var result = [];

  function make_f(item, i){
    //item and i are now private variables of make_f
    //and wont be shared by the returned closure
    // the other variable in scope (list) is not shadowed so
    // it is still shared but that is not a problem since we
    // never change its value.
    return function() { alert(item + ' ' + list[i]) };
  }

  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push( make_f(item, i) );
  }
  return result;
}

您也可以使用立即调用的匿名函数((function(){}())模式)执行相同的操作。

function buildList(list) { 
  var result = [];

  for (var i = 0; i < list.length; i++) {
    var item = 'item' + list[i];
    result.push( (function (item, i){
        return function(){function() {alert(item + ' ' + list[i])};
    })(item, i) );
  }

  return result;
}

答案 2 :(得分:1)

把它放进......另一个封闭!

function buildList(list) { 
  var result = [];
  for (var i = 0; i < list.length; i++) {
    result.push((function(item, listItem){
      return function() {
        alert(item + ' ' + listItem);
      };
    })('item' + list[i], 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();

答案 3 :(得分:0)

var具有函数作用域,但如果使用let,则将获得块作用域。

所以我会做: for(让我= 0;我