循环和闭包。 For 和 Var

Posted

技术标签:

【中文标题】循环和闭包。 For 和 Var【英文标题】:Loops and closures. For and Var 【发布时间】:2018-05-02 12:26:19 【问题描述】:

我找到了很多解释这个问题的主题,关于如何使用 var 修复以下代码,比如这个 http://conceptf1.blogspot.com/2013/11/javascript-closures.html 或者这个JavaScript closure inside loops – simple practical example。

但我真的不明白为什么它在使用 var 时不起作用而在使用 let 时起作用。

var funcs = [];        
for (var i = 0; i < 3; i++)         //  let's create 3 functions
  funcs[i] = function()             //  and store them in funcs
    console.log("My value: " + i);   //  each should log its value.
  ;

for (var j = 0; j < 3; j++) 
  funcs[j]();                        //  and now let's run each one to see

// outputs 3 3 3

我真的不知道......

【问题讨论】:

你的意思是“使用var时不工作而使用let时工作”? Explanation of `let` and block scoping with for loops的可能重复 我检查了所有其他重复项,我无法理解它们,只有下面的答案帮助我理解了这个问题。 【参考方案1】:

因为 var 是函数范围的(即具有周围函数的范围),而 letconst 是块范围的 - 因此在每个块中都有自己的值(可能是 @987654324 @- 或else-block 或循环的每次迭代,如您的情况)。块范围的变量未在块外定义。函数范围的变量会一直保留到函数结束。

您的i 变量是函数范围的,这意味着一旦您的循环完成,它仍然存在于第一个循环之外并且其值为3。因此,一旦您调用数组函数,它就会从上层范围(即3)获取i 并输出它。例如,如果您使用 let,您将获得每次迭代的新绑定,并且您的 i 的值将保留初始声明值。

编辑: 所以为了输出顺序值,需要将var替换为let

for (let i = 0; i < 3; i++) 
  funcs[i] = function() 
    // now `i` is bound to the scope & keeps its initial value
    console.log("My value: " + i); 
  ;

【讨论】:

您能否在我的答案中添加重写的代码,以便我可以轻松理解发生了什么?是不是像:var i = 0;对于 (i; i 我知道如何让它工作,所有其他帖子和主题都给了我一个答案,但我真的不明白为什么使用 var 的初始解决方案不起作用......也许还有其他一些代码示例我能理解吗? @Marek,如果您的问题是“但我真的不明白为什么使用 var 的初始解决方案不起作用”那么您应该这么说,并且您不应该排除 @ 987654335@ 在那里,因为打开另一个问题会混淆,我邀请您编辑您的帖子以反映您真正想知道的内容【参考方案2】:

ES6's let 是块作用域,这意味着它在 内部拥有自己的作用域,就像许多其他传统语言一样。但相比之下,var 在您的代码中是一个全局变量。

在第一个for 循环中,function 仅分配给func[i] 3 次,最终值为 3,但未执行。如果您首先在loop 中执行该函数,您将获得预期的输出:

var funcs = [];
for (var i = 0; i < 3; i++)       // let's create 3 functions
  funcs[i] = function()           // and store them in funcs
    console.log("My value: " + i); // each should log its value.
  ;
  funcs[i](); // execution of func

所以,重要的是你的函数在哪个上下文中执行。

现在,在您的代码中第一次执行 funcs[j]() 时,i 的值已经是 3。如果要记录增量值,则必须将其作为参数传递,如下所示:

var funcs = [];
for (var i = 0; i < 3; i++)       // let's create 3 functions
  funcs[i] = function(j)           // and store them in funcs
    console.log("My value: " + j); // each should log its value.
  ;

for (var j = 0; j < 3; j++) 
  funcs[j](j);                      // and now let's run each one to see

【讨论】:

我想我现在开始明白了。所以这行代码 -> console.log("My value:" + i);使用 var 时会使用全局 i (3) 值吗?如果我使用 let,每次迭代都会为函数定义保持不同的 i 值? 所以基本上,3 次迭代将“生成”3 个块作用域? 我认为这是迄今为止我找到的最好的解释。谢谢【参考方案3】:

let 不同,var 被提升到循环范围之外。实际上,您的 i 变量将始终等于最后一次迭代(在您的示例中为 3)。 let 没有这个问题,因为它没有被吊起。

【讨论】:

以上是关于循环和闭包。 For 和 Var的主要内容,如果未能解决你的问题,请参考以下文章

JS闭包导致循环给按钮添加事件时总是执行最后一个

js闭包

经典面试题,循环中使用闭包解决 var 定义函数的问题--闭包

浅谈闭包

JavaScript之全选/反选/取消,for循环闭包

for循环中的闭包