如何将JS变量的值(而不是引用)传递给函数?

时间:2010-04-02 20:20:24

标签: javascript closures pass-by-reference listener pass-by-value

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

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的引用?

6 个答案:

答案 0 :(得分:161)

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

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

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

答案 1 :(得分:35)

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

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

i in的值作为参数传递给函数。 (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))
            );
        };
    };
}

答案 2 :(得分: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);
}

EDIT,2013: 现在这些通常被称为IIFE

答案 3 :(得分:2)

你闭嘴了。 Here's an article on closures以及如何使用它们。查看页面上的示例5;这就是你正在处理的情景。

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

答案 4 :(得分:-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)); 
}

答案 5 :(得分:-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);
 }); 
}

我还没有测试过它。