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

请解释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;


不负相思意
浏览 345回答 3
3回答

BIG阳

长答案这是直接从我在一家内部公司写的一篇文章中复制出来的:问:如何正确使用循环中的闭包?快速回答:使用函数工厂。&nbsp;&nbsp;for&nbsp;(var&nbsp;i=0;&nbsp;i<10;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;document.getElementById(i).onclick&nbsp;=&nbsp;(function(x){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(x); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;})(i); &nbsp;&nbsp;}或者更容易读的版本:&nbsp;&nbsp;function&nbsp;generateMyHandler&nbsp;(x)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(x); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;} &nbsp;&nbsp;for&nbsp;(var&nbsp;i=0;&nbsp;i<10;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;document.getElementById(i).onclick&nbsp;=&nbsp;generateMyHandler(i); &nbsp;&nbsp;}这常常会混淆那些刚开始使用javascript或函数式编程的人。这是误解什么是闭包的结果。闭包不仅传递变量的值,甚至传递对变量的引用。闭包捕获变量本身!下面的代码说明了这一点:&nbsp;&nbsp;var&nbsp;message&nbsp;=&nbsp;'Hello!'; &nbsp;&nbsp;document.getElementById('foo').onclick&nbsp;=&nbsp;function(){alert(message)}; &nbsp;&nbsp;message&nbsp;=&nbsp;'Goodbye!';单击元素‘foo’将生成一个警告框,其中包含以下消息:“再见!”因此,在循环中使用简单的闭包将导致所有闭包共享相同的变量,并且该变量将包含在循环中分配给它的最后一个值。例如:&nbsp;&nbsp;for&nbsp;(var&nbsp;i=0;&nbsp;i<10;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;document.getElementById('something'+i).onclick&nbsp;=&nbsp;function(){alert(i)}; &nbsp;&nbsp;}单击所有元素时,都会生成一个数字为10的警告框。i="hello";所有元素现在将生成一个“Hello”警报!变量i在十个函数之间共享,再加上当前函数/作用域/上下文。把它看作是一种私有的全局变量,只有涉及到的函数才能看到。我们需要的是该变量的实例,或者至少是对变量的简单引用,而不是变量本身。幸运的是,javascript已经有了传递引用(对象)或值(用于字符串和数字)的机制:函数参数!在javascript中调用函数时,如果函数是对象,则通过引用传递该函数的参数;如果函数是字符串或数字,则传递值。这足以破坏闭包中的变量共享。因此:&nbsp;&nbsp;for&nbsp;(var&nbsp;i=0;&nbsp;i<10;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;document.getElementById(i).onclick&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(function(x){&nbsp;/*&nbsp;we&nbsp;use&nbsp;this&nbsp;function&nbsp;expression&nbsp;simply&nbsp;as&nbsp;a&nbsp;factory &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to&nbsp;return&nbsp;the&nbsp;function&nbsp;we&nbsp;really&nbsp;want&nbsp;to&nbsp;use:&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;we&nbsp;want&nbsp;to&nbsp;return&nbsp;a&nbsp;function&nbsp;reference &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;so&nbsp;we&nbsp;write&nbsp;a&nbsp;function&nbsp;expression*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;function(){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(x);&nbsp;/*&nbsp;x&nbsp;here&nbsp;refers&nbsp;to&nbsp;the&nbsp;argument&nbsp;of&nbsp;the&nbsp;factory&nbsp;function &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;captured&nbsp;by&nbsp;the&nbsp;'inner'&nbsp;closure&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;The&nbsp;brace&nbsp;operators&nbsp;(..)&nbsp;evaluates&nbsp;an&nbsp;expression,&nbsp;in&nbsp;this&nbsp;case&nbsp;this &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;expression&nbsp;which&nbsp;yields&nbsp;a&nbsp;function&nbsp;reference.&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;})(i)&nbsp;/*&nbsp;The&nbsp;function&nbsp;reference&nbsp;generated&nbsp;is&nbsp;then&nbsp;immediately&nbsp;called() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;where&nbsp;the&nbsp;variable&nbsp;i&nbsp;is&nbsp;passed&nbsp;*/ &nbsp;&nbsp;}

白衣非少年

在这种情况下,闭包的“问题”是,任何访问i引用相同的变量。那是因为ECMA-/Javascripts&nbsp;function scope或lexical scope.所以为了避免每次打电话到alert(i);会显示5(因为在循环完成后,i=5),您需要创建一个在运行时调用自己的新函数。要实现这一点,您需要创建一个新的函数,另外,您还需要在最后进行额外的偏执,以便invoke the outer function立刻,所以link.onclick现在将返回的函数作为引用。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript