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

发布于 2024-08-27 04:29:43 字数 313 浏览 15 评论 0原文

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

原野 2024-09-03 04:29:43

在现代浏览器中,您可以使用 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);
}

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

In modern browsers, you can use the let or const keywords to create a block-scoped variable:

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

By creating an anonymous function and calling it with the variable as the first argument, you're passing-by-value to the function and creating a closure.

揽月 2024-09-03 04:29:43

除了闭包之外,您还可以使用 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))
            );
        };
    };
}

As well as the closures, you can use function.bind:

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

passes the value of i in as an argument to the function when called. (null is for binding this, which you don't need in this case.)

function.bind was introduced by the Prototype framework and has been standardised in ECMAScript Fifth Edition. Until browsers all support it natively, you can add your own function.bind support using closures:

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))
            );
        };
    };
}
写下不归期 2024-09-03 04:29:43

关闭:

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

closures:

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:
These are now commonly referred to as an IIFE

骷髅 2024-09-03 04:29:43

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

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

You're winding up with a closure. 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.

EDIT: Four years later, that link is dead. The root of the issue above is that the for loop forms closures (specifically on marker = results[i]). As marker is passed into addEventListener, you see the side effect of the closure: the shared "environment" is updated with each iteration of the loop, before it's finally "saved" via the closure after the final iteration. MDN explains this very well.

囍孤女 2024-09-03 04:29:43
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)); 
}
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)); 
}
凑诗 2024-09-03 04:29:43

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

不过我还没有测试过。

I think we can define a temporary variable to store the value of 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);
 }); 
}

I haven't tested it though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文