JavaScript:您可以在创建时将变量替换为匿名函数吗?

发布于 2024-09-17 18:47:45 字数 418 浏览 13 评论 0原文

可能的重复:
循环内的 JavaScript 闭包 - 简单的实际示例

而不是解释问题,我举一个例子:

for (var i = 0; i < 100; i ++) {
  get_node(i).onclick = function() {
    do_something_very_important(i);
  }
}

有什么方法可以在创建而不是执行时将 i 的值替换到函数中吗?谢谢。

Possible Duplicate:
Javascript closure inside loops - simple practical example

Rather than explaining the question, I'll give an example:

for (var i = 0; i < 100; i ++) {
  get_node(i).onclick = function() {
    do_something_very_important(i);
  }
}

Is there any way to have the value of i substituted into the function upon creation rather than execution? Thanks.

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

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

发布评论

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

评论(2

酷到爆炸 2024-09-24 18:47:46

是的,这有效...

for (var i = 0; i < 100; i++) {
  get_node(i).onclick = (function(i) {
    return function () {
      do_something_very_important(i);
    }
  })(i);
}

Yes this works...

for (var i = 0; i < 100; i++) {
  get_node(i).onclick = (function(i) {
    return function () {
      do_something_very_important(i);
    }
  })(i);
}
面如桃花 2024-09-24 18:47:45

是的,您可以,但这不适用于您提供的示例。您可能会遇到一个非常常见的闭包问题,其中 <代码>for循环。

闭包中包含的变量共享相同的单一环境,因此当调用 onclick 回调时,for 循环将运行其进程,并且 i 变量将指向最后分配的值。在您的示例中,do_something_very_important() 函数将为每个节点传递值 100,这不是您想要的。

您可以使用函数工厂通过更多的闭包来解决这个问题:

function makeClickHandler(i) {  
  return function() {  
    do_something_very_important(i);
  };  
}

// ...

for(var i = 0; i < 100; i++) {
  get_node(i).onclick = makeClickHandler(i);
}

如果您不熟悉闭包的工作原理,这可能是一个相当棘手的话题。您可能需要查看以下 Mozilla 文章以获取简要介绍:


更新:

您还可以将上述函数工厂内联为 @adamse 在其他答案中建议。这实际上是一种更常见的方法,但实际上与上面的相同:

for(var i = 0; i < 100; i++) {
  get_node(i).onclick = (function(p) {
    return function () {
      // we could have used i as a parameter variable as well,
      // but we're using p to better illustrate what's happening
      do_something_very_important(p); 
    }
  })(i);
}

任何另一种解决方案都是通过使用自调用匿名函数将每个迭代封闭在其自己的范围内:

for(var i = 0; i < 100; i++) {
  (function (p) {
    // we now have a separate closure environment for each
    // iteration of the loop
    get_node(i).onclick = function() {
      do_something_very_important(p);
    }
  })(i);
}

Yes, you can, but that won't work for the example you provided. You would be having a very common closure problem in that for loop.

Variables enclosed in a closure share the same single environment, so by the time the onclick callback is called, the for loop will have run its course, and the i variable will be left pointing to the last value it was assigned. In your example, the do_something_very_important() function will be passed the value 100 for each node, which is not what you intend.

You can solve this problem with even more closures, using a function factory:

function makeClickHandler(i) {  
  return function() {  
    do_something_very_important(i);
  };  
}

// ...

for(var i = 0; i < 100; i++) {
  get_node(i).onclick = makeClickHandler(i);
}

This can be quite a tricky topic, if you are not familiar with how closures work. You may want to check out the following Mozilla article for a brief introduction:


UPDATE:

You could also inline the above function factory as @adamse suggested in the other answer. This is actually a more common approach, but is practically the same as the above:

for(var i = 0; i < 100; i++) {
  get_node(i).onclick = (function(p) {
    return function () {
      // we could have used i as a parameter variable as well,
      // but we're using p to better illustrate what's happening
      do_something_very_important(p); 
    }
  })(i);
}

Any yet another solution is to enclose each iteration in its own scope, by using self invoking anonymous functions:

for(var i = 0; i < 100; i++) {
  (function (p) {
    // we now have a separate closure environment for each
    // iteration of the loop
    get_node(i).onclick = function() {
      do_something_very_important(p);
    }
  })(i);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文