为了账号安全,请及时绑定邮箱和手机立即绑定

请解释JavaScript闭包在循环中的用法

请解释JavaScript闭包在循环中的用法

不负相思意 2019-07-10 15:26:34
请解释JavaScript闭包在循环中的用法我读过许多关于循环内部闭包和闭包的解释。我很难理解这个概念。我有这样的代码:是否有办法尽可能地减少代码,从而使闭包的概念更加清晰。我很难理解i在两个括号内。谢谢function addLinks () {     for (var i=0, link; i<5; i++) {         link = document.createElement("a");         link.innerHTML = "Link " + i;         link.onclick = function (num) {             return function () {                 alert(num);             };         }(i);         document.body.appendChild(link);     }}window.onload = addLinks;
查看完整描述

3 回答

?
BIG阳

TA贡献1859条经验 获得超6个赞

长答案

这是直接从我在一家内部公司写的一篇文章中复制出来的:

问:如何正确使用循环中的闭包?快速回答:使用函数工厂。

  for (var i=0; i<10; i++) {
    document.getElementById(i).onclick = (function(x){
      return function(){
        alert(x);
      }
    })(i);
  }

或者更容易读的版本:

  function generateMyHandler (x) {
    return function(){
      alert(x);
    }
  }

  for (var i=0; i<10; i++) {
    document.getElementById(i).onclick = generateMyHandler(i);
  }

这常常会混淆那些刚开始使用javascript或函数式编程的人。这是误解什么是闭包的结果。

闭包不仅传递变量的值,甚至传递对变量的引用。闭包捕获变量本身!下面的代码说明了这一点:

  var message = 'Hello!';
  document.getElementById('foo').onclick = function(){alert(message)};
  message = 'Goodbye!';

单击元素‘foo’将生成一个警告框,其中包含以下消息:“再见!”因此,在循环中使用简单的闭包将导致所有闭包共享相同的变量,并且该变量将包含在循环中分配给它的最后一个值。例如:

  for (var i=0; i<10; i++) {
    document.getElementById('something'+i).onclick = function(){alert(i)};
  }

单击所有元素时,都会生成一个数字为10的警告框。i="hello";所有元素现在将生成一个“Hello”警报!变量i在十个函数之间共享,再加上当前函数/作用域/上下文。把它看作是一种私有的全局变量,只有涉及到的函数才能看到。

我们需要的是该变量的实例,或者至少是对变量的简单引用,而不是变量本身。幸运的是,javascript已经有了传递引用(对象)或值(用于字符串和数字)的机制:函数参数!

在javascript中调用函数时,如果函数是对象,则通过引用传递该函数的参数;如果函数是字符串或数字,则传递值。这足以破坏闭包中的变量共享。

因此:

  for (var i=0; i<10; i++) {
    document.getElementById(i).onclick =
      (function(x){ /* we use this function expression simply as a factory
                       to return the function we really want to use: */

        /* we want to return a function reference
           so we write a function expression*/
        return function(){
          alert(x); /* x here refers to the argument of the factory function
                       captured by the 'inner' closure */
        }

      /* The brace operators (..) evaluates an expression, in this case this
         function expression which yields a function reference. */

      })(i) /* The function reference generated is then immediately called()
               where the variable i is passed */
  }


查看完整回答
反对 回复 2019-07-10
?
白衣非少年

TA贡献1155条经验 获得超0个赞

在这种情况下,闭包的“问题”是,任何访问i引用相同的变量。那是因为ECMA-/Javascripts function scopelexical scope.

所以为了避免每次打电话到alert(i);会显示5(因为在循环完成后,i=5),您需要创建一个在运行时调用自己的新函数。

要实现这一点,您需要创建一个新的函数,另外,您还需要在最后进行额外的偏执,以便invoke the outer function立刻,所以link.onclick现在将返回的函数作为引用。


查看完整回答
反对 回复 2019-07-10
  • 3 回答
  • 0 关注
  • 344 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信