CMS*_*ing 56 javascript closures scope loops
我已经阅读了关于循环内的闭包和闭包的一些解释.我很难理解这个概念.我有这样的代码:有没有办法尽可能地减少代码,因此闭包的概念可以更清晰.我很难理解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;
Run Code Online (Sandbox Code Playgroud)
sle*_*man 114
警告:长(ish)答案
这是直接从我在内部公司维基中写的文章中复制的:
问题:如何在循环中正确使用闭包?快速回答:使用功能工厂.
for (var i=0; i<10; i++) {
document.getElementById(i).onclick = (function(x){
return function(){
alert(x);
}
})(i);
}
Run Code Online (Sandbox Code Playgroud)
或者更容易阅读的版本:
function generateMyHandler (x) {
return function(){
alert(x);
}
}
for (var i=0; i<10; i++) {
document.getElementById(i).onclick = generateMyHandler(i);
}
Run Code Online (Sandbox Code Playgroud)
这通常会让那些不熟悉javascript或函数式编程的人感到困惑.这是误解闭包的结果.
闭包不仅传递变量的值,甚至传递变量的引用.闭包捕获变量本身!以下代码说明了这一点:
var message = 'Hello!';
document.getElementById('foo').onclick = function(){alert(message)};
message = 'Goodbye!';
Run Code Online (Sandbox Code Playgroud)
单击元素'foo'将生成一个警告框,其中包含以下消息:"Goodbye!".因此,在循环中使用简单闭包将最终使所有闭包共享相同的变量,并且该变量将包含在循环中分配给它的最后一个值.例如:
for (var i=0; i<10; i++) {
document.getElementById('something'+i).onclick = function(){alert(i)};
}
Run Code Online (Sandbox Code Playgroud)
单击时所有元素将生成一个数字为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 */
}
Run Code Online (Sandbox Code Playgroud)
gna*_*arf 10
我已经用JavaScript编程了很长时间,而且"循环闭包"是一个非常广泛的话题.我假设您正在讨论在(function(param) { return function(){ ... }; })(param);
for循环内部使用的实践,以便在内部函数稍后执行时保留循环的"当前值"...
for(var i=0; i<4; i++) {
setTimeout(
// argument #1 to setTimeout is a function.
// this "outer function" is immediately executed, with `i` as its parameter
(function(x) {
// the "outer function" returns an "inner function" which now has x=i at the
// time the "outer function" was called
return function() {
console.log("i=="+i+", x=="+x);
};
})(i) // execute the "closure" immediately, x=i, returns a "callback" function
// finishing up arguments to setTimeout
, i*100);
}
Run Code Online (Sandbox Code Playgroud)
i==4, x==0
i==4, x==1
i==4, x==2
i==4, x==3
Run Code Online (Sandbox Code Playgroud)
正如您在输出中看到的那样,所有内部回调函数都指向相同的i
,但是,由于每个函数都有自己的"闭包",因此值x
实际上存储为i
外部函数执行时的任何值.
通常,当您看到此模式时,您将使用与参数相同的变量名称和外部函数的参数:(function(i){ })(i)
例如.该函数内的任何代码(即使稍后执行,如回调函数)将i
在您调用"外部函数"时引用.