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

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

本问题已经有最佳答案,请猛点这里访问。

下面是我尝试运行的某个简化版本:

1
2
3
4
5
6
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?


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

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

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

1
2
3
4
5
6
7
8
for (var i = 0; i < results.length; i++) {
  (function (i) {
    marker = results[i];
    google.maps.event.addListener(marker, 'click', function() {
      change_selection(i);
    });
  })(i);
}

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


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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
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))
            );
        };
    };
}


闭包:

1
2
3
4
5
6
7
8
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:这些现在通常被称为生命


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

编辑:四年后,那个链接就死了。上述问题的根源在于for循环形成闭包(特别是在marker = results[i]上)。当marker被传递到addEventListener中时,您会看到闭包的副作用:共享的"环境"随着循环的每次迭代而更新,然后在最终迭代之后通过闭包最终"保存"它。MDN对此解释得很好。


1
2
3
4
5
6
7
8
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));
}


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

1
2
3
4
5
6
7
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);
 });
}

不过我还没有测试过。