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

rya*_*yan 116 javascript closures listener pass-by-reference pass-by-value

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

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

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

And*_*y E 162

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

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

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

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

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

  • 您需要在`marker`之前添加`var`以不污染全局命名空间. (4认同)
  • @ThiefMaster:奇怪的是,我在一段时间内第一次看到这个答案之后就想到了同样的事情.但是,看看OP的代码,我们不能完全确定`marker`不是全局变量. (2认同)

bob*_*nce 35

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

google.maps.event.addListener(marker, 'click', change_selection.bind(null, i));
Run Code Online (Sandbox Code Playgroud)

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))
            );
        };
    };
}
Run Code Online (Sandbox Code Playgroud)

  • 刚注意到这一点,+ 1.我非常喜欢`bind`,不能等待本机实现推出. (2认同)
  • @NoBugs:目前:IE9 +.Fx4 +,最近的Chrome和Opera版本.不是Safari,不是iPhone,Android浏览器自冰淇淋三明治以来就有它. (2认同)

Dav*_*och 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);
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我不确定你理解downvoting的原因.除了Andy的(优秀)答案之外,这个答案确实增加了信息:IIFE. (4认同)