118

这是我正在尝试运行的简化版本:

for (var i = 0; i < results.length; i++) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() { 
        change_selection(i);
    }); 
}

但我发现每个侦听器都使用 results.length 的值(for 循环终止时的值)。如何添加侦听器,以便每个侦听器在添加时都使用 i 的值,而不是对 i 的引用?

4

6 回答 6

161

在现代浏览器中,您可以使用letorconst关键字来创建块范围变量:

for (let i = 0; i < results.length; i++) {
  let marker = results[i];
  google.maps.event.addListener(marker, 'click', () => change_selection(i));
}

在较旧的浏览器中,您需要创建一个单独的范围,通过将变量作为函数参数传递来将其保存在当前状态:

for (var i = 0; i < results.length; i++) {
  (function (i) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() { 
      change_selection(i);
    }); 
  })(i);
}

通过创建一个匿名函数并将变量作为第一个参数调用它,您将按值传递给函数并创建一个闭包。

于 2010-04-02T20:24:28.363 回答
35

除了闭包,您还可以使用function.bind

google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));

调用时将 in的值i作为参数传递给函数。(null用于绑定this,在这种情况下您不需要。)

function.bind由 Prototype 框架引入,并已在 ECMAScript 第五版中标准化。在浏览器都原生支持之前,您可以function.bind使用闭包添加自己的支持:

if (!('bind' in Function.prototype)) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}
于 2010-04-02T22:19:35.487 回答
13

关闭:

for (var i = 0, l= results.length; i < l; i++) {
    marker = results[i];
    (function(index){
        google.maps.event.addListener(marker, 'click', function() { 
            change_selection(index);
        }); 
    })(i);
}

编辑,2013 年: 这些现在通常被称为IIFE

于 2010-04-02T20:25:38.370 回答
2

你要结束了。这是一篇关于闭包以及如何使用它们的文章。查看页面上的示例 5;这就是你正在处理的场景。

编辑:四年后,该链接已失效。上述问题的根源是for循环形成闭包(特别是在 上marker = results[i])。在marker传入addEventListener时,您会看到闭包的副作用:共享的“环境”随着循环的每次迭代而更新,然后在最终迭代之后通过闭包最终“保存”。MDN 很好地解释了这一点。

于 2010-04-02T20:24:30.233 回答
-2
for (var i = 0; i < results.length; i++) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', (function(i) {
        return function(){
            change_selection(i);
        }
    })(i)); 
}
于 2014-05-17T15:45:58.130 回答
-4

我认为我们可以定义一个临时变量来存储 i 的值。

for (var i = 0; i < results.length; i++) {
 var marker = results[i];
 var j = i;
 google.maps.event.addListener(marker, 'click', function() { 
   change_selection(j);
 }); 
}

不过我还没有测试过。

于 2012-06-06T17:20:56.863 回答