How do I pass the value (not the reference) of a JS variable to a function?

Here is a simplified version of something I'm trying to run:

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

but I'm finding that every listener uses the value of results.length (the value when the for loop terminates). How can I add listeners such that each uses the value of i at the time I add it, rather than the reference to i?

46923 次浏览

在现代浏览器中,您可以使用 letconst关键字来创建块作用域变量:

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

In older browsers, you need to create a separate scope that saves the variable in its current state by passing it as a function parameter:

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

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

你要做个了结,Here's an article on closures and how to work with them. Check out Example 5 on the page; that's the scenario you're dealing with.

编辑: 四年后,这个链接死了。上述问题的根源是 for循环形成闭包(特别是在 marker = results[i]上)。当将 marker传递到 addEventListener时,您将看到闭包的副作用: 共享“环境”随循环的每次迭代而更新,然后在最后一次迭代之后通过闭包最终“保存”。MDN explains this very well.

关闭:

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

除了闭包之外,还可以使用 function.bind:

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

在调用时将 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))
);
};
};
}

我想我们可以定义一个临时变量来存储 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);
});
}

我还没测试过。

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