2014-11-01 167 views
1

我做了一些研究后放弃了这一点。我的问题如下:Javascript关闭与循环

post,我了解以下代码。

var funcs = {}; 
for (var i = 0; i < 3; i++) {   // let's create 3 functions 
funcs[i] = function() {   // and store them in funcs 
    var item = "item" + i;   // inside 
    console.log("item: " + item + ", i: " + i); // each should log its value. 
    }; 
} 
for (var j = 0; j < 3; j++) { 
    funcs[j]();      // and now let's run each one to see 
} 

Result: 
item: item3, i: 3 
item: item3, i: 3 
item: item3, i: 3 

但如果我更改移动var item = "item" + i之外的功能(),结果会有所不同。为什么是这样?

var funcs = {}; 
for (var i = 0; i < 3; i++) {   // let's create 3 functions 
    var item = "item" + i;    // outside 
    funcs[i] = function() {   // and store them in funcs 
     console.log("item: " + item + ", i: " + i); // each should log its value. 
    }; 
} 
for (var j = 0; j < 3; j++) { 
    funcs[j]();      // and now let's run each one to see 
} 

Result: 
item: item2, i: 3 
item: item2, i: 3 
item: item2, i: 3 
+0

真正的问题是你的声明和'i'变量的用法。它保持在最高级别的范围内,但是您可以在关闭中使用它。当你“关闭”,现在让我们跑......“。那么'i'变量(用于for(;;)将会完成它的循环并且显示值 – 2014-11-01 09:38:44

回答

1

你面临的关键问题是一个闭包通过引用而不是按值来捕获变量。例如:

var i = 0; 
var f = function(){ i++; console.log(i); } 
var g = function(){ i++; console.log(i); } 
f(); g(); f(); g(); 

这将显示1,2,3,4,因为fg和不捕获变量i的值,但变量本身,因此都突变相同的变量。

一个非常常见的错误是创建在一个循环中的多个闭合忘记他们都将捕获相同的变量(在循环中使用的一个),因此,当这个环路变量被递增所有已创建的封闭件将看到它的变化。例如,在你的代码

for (var i = 0; i < 3; i++) { 
    funcs[i] = function() { 
     var item = "item" + i; // inside 
     console.log("item: " + item + ", i: " + i); 
    }; 
} 

item是一个局部变量的函数,但i,而不是来自于外界,它的所有的人共享。由此可以看出,例如与

i = 42; 
funcs[0](); funcs[1](); funcs[2](); // Displays 42 three times 
i = 99; 
funcs[0](); funcs[1](); funcs[2](); // Now they all display 99 

在你的问题的东西第二种情况下都只是略有不同,因为在

for (var i = 0; i < 3; i++) { 
    var item = "item" + i; 
    funcs[i] = function() { 
     console.log("item: " + item + ", i: " + i); 
    }; 
} 

item变量现在共享,因为它的定义功能外并关闭它捕获它。在显示屏中,您可以看到分配给它的最后一个值。

关键的一点是要记住,在Javascript中的变量是本地的功能,不是本地的{...}块(像它在C++例如),并因此鉴别因素是,如果变量的函数内声明或者在函数之外,如果它们是在循环内部或外部声明的话。

为了克服这个共同的问题,并为每个中的回路形成的封闭的单独的索引你经常会看到这样

var f = (function(i){return function(){ ... };})(i); 

其中创建函数,立即调用返回另一个函数的代码。

的原因是创建一个单独的新变量的唯一方法是一个功能,留给我们创建一个返回函数的函数的模式:在这种情况下有用的闭合(内)将捕获每个迭代的变量都不相同(因为它是外部参数)。

改变你的代码

for (var i = 0; i < 3; i++) { 
    funcs[i] = (function(i){return function() { 
     var item = "item" + i; 
     console.log("item: " + item + ", i: " + i); 
    };})(i); 
} 

可以发挥预期的(即每个函数现在有自己的i值)。

+0

谢谢。但是,请问你回答这个问题:什么是我的代码1和2之间的区别是什么?为什么把'var item'放在循环之外会产生影响? – 2014-11-04 21:54:07

+1

@ls .:问题不在循环外部,而是在**函数内部或外部**。除了函数外,它是一个由所有函数共享的变量,如果它在函数内部,那么它是每个函数的不同变量。 – 6502 2014-11-04 22:26:31

+0

我想我已经得到了它!如果你可以添加这个评论,即'如果项目在外面。 ..如果它在你的答案里面......“我会投票给它作为答案。 (因为我真的没有得到你的原始答案)。非常感谢 – 2014-11-06 01:05:58

0

item变量不存在,直到函数的第一种情况下运行时,在该点它是本地的每个功能和获取设置等于"item" + i。而i3,因为它在外部范围内声明,3是循环结束时的情况。

在第二种情况下,item变量存在于功能包含范围 - 的相同的范围内i - 和所述第一循环的最后迭代期间已被设定到"item2"。在该循环中,i的值为0,1,2 - 循环结束时仅设置为3

+0

我还是不明白在第二种情况下,为什么我在'console.log() '得到3这是循环结束时的值,而我在'item'得到2,这是最后一次迭代的值?是什么引起这种差异的主要问题以及为什么? – 2014-11-01 11:40:31