我已经阅读了许多有关闭包和循环内闭包的解释。我很难理解这个概念。我有以下代码:有没有办法尽可能减少代码,以便可以使闭包的概念更清晰。我很难理解其中i两个括号内的部分。谢谢
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;
警告:长(ish)答案
这是直接从我在公司内部Wiki中写的文章中复制的:
问题:如何在循环中正确使用闭包?快速解答:使用功能工厂。
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在十个函数加上当前函数/作用域/上下文之间共享。可以将其视为只有相关函数才能看到的一种私有全局变量。
i="hello";
我们想要的是该变量的实例,或者至少是对该变量的简单引用,而不是变量本身。幸运的是,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 */ }