2016-12-15 72 views
-2

说我有这个功能:IIFE和Javascript中的变量赋值。我们真的需要一个IIFE吗?到底是怎么回事?

function printFruits(fruits) { 
    for (var i = 0; i < fruits.length; i++) { 
     setTimeout(function() { 
      console.log(fruits[i]); 
     }, i * 1000); 
    } 
} 

printFruits(["Lemon", "Orange", "Mango"]) 

所以这将返回undefined 3倍。

我可以在一个较高水平,自变量是按值,而是由瓶盖内引用不存储...循环正在整理第一,由当时的功能从说不定事件循环离队看到的...变量已处于未定义状态(fruits.length的计算结果为3,这对于此数组大小而言过高)。但为什么这个表现奇怪......它打印“苹果”3次。

function printFruits(fruits) { 
     for (var i = 0; i < fruits.length; i++) { 
      var someConstant = i; 
      setTimeout(function() { 
       console.log(fruits[someConstant]); 
      }, someConstant * 100); 
     } 
    } 

printFruits(["mango", "banana", "apple"]) 

不应该someConstant会改变以及我吗?为什么它总是2?

而且这个工程:

function printFruits(fruits) { 
     for (var i = 0; i < fruits.length; i++) { 
     (function() { 
      var current = i; 
       setTimeout(function() { 
       console.log(fruits[current]); 
       }, current * 1000); 
      })(); 
     } 
    } 

为什么是必要的IIFE来解决这个问题?

+1

“不应该一些常数也会随着”而改变 - 这会引发一个参考错误,因为你从不定义'someCosntant'(拼写!)。如果我修复了这个错误...它不起作用:http://jsbin.com/yegimi/1/edit?js,console尝试创建真实的[mcve]。最好使用[live demos](https://stackoverflow.blog/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/)。 – Quentin

+2

定义“作品”。这个代码不是三次显示芒果吗? – deceze

+0

'someConstant'和'i'都在相同的范围内定义。 'someConstant'只是'i'的别名。因此它有相同的根本问题,即使结果略有不同。这整个事情是一个* scope *的问题。只有创建一个新的范围才能解决问题。将更多变量添加到相同的作用域不会。 –

回答

1

不同的是,someConstant永远不会被最后一次迭代后递增。 for()环路集合i = 3,测试i < fruits.length失败,因此循环停止。结果,someConstant仍然设置为2从循环的最后一次迭代。然后所有的回调都会运行,所以它们都记录fruits[2],即Mango

您需要IIFE来获得每次迭代以将其值i保存在闭包中。

2

这些样品之间唯一的区别是,for循环增量i3停止之前,而被分配给someConstant的最后一个值是2。您的“工作”代码输出Mango三次(数组的索引2)而不是undefined(数组的索引3)。一般的行为是一样的。

是的,你需要一个IIFE或ES6的let关键字,而不是var

3

第二实施例

function printFruits(fruits) { 
 
    for (var i = 0; i < fruits.length; i++) { 
 
    var someConstant = i; 
 
    setTimeout(function() { 
 
     console.log(fruits[someConstant]); 
 
    }, someConstant * 1000); 
 
    } 
 
} 
 
printFruits(["Lemon", "Orange", "Mango"])

这将记录三次芒果。因为每次someConstant变量都被创建并重新初始化为i。回想一下循环工作的方式。 i值在这里增加到4,检查条件4 < 3,并终止。所以循环内部的事情只执行三次。所以在printFruits函数作用域中定义的someConstant的最后一个值是2.所以当内部函数执行某个常量时,它的值等于2.所以我们每次都得到芒果。

第三个例子

function printFruits(fruits) { 
 
    for (var i = 0; i < fruits.length; i++) { 
 
    (function() { 
 
     var current = i; 
 
     setTimeout(function() { 
 
     console.log(fruits[current]); 
 
     }, current * 1000); 
 
    })(); 
 
    } 
 
} 
 

 
printFruits(["Lemon", "Orange", "Mango"])

这里封锁发生的美。这里立即执行一个自动执行的函数。所以当我= 1时,它立即调用。现在每个功能都有不同的范围。有一个单独的当前值为每个定义。因此,稍后当它执行时,它会在其范围内定义时重新收集'current'的值。

+0

*“因为每次someConstant变量都被创建并重新初始化为i。”*这不太正确。在程序的整个生命周期中,只有一个'someConstant'变量,它在代码执行之前创建。会发生什么是'someConstant'只是被赋予'i'的当前值。 –

+0

@FelixKling嗨,但有一个'var someConstant'。 *简单地分配当前值*是我们var devlare一次并赋值时发生的事情,是否应该有多个同名的变量创建?说第一个var语句,有一个内存分配。当我们再次做var时,会发生什么?它是否会覆盖分配,并重新对值进行重新分配?我的意思是,如果没有var被使用,那么这些东西会有多不同。 – Ayan

+0

在执行任何代码之前处理所有'var'声明。所以'var foo = 42;'与'var foo基本相同;/*其他代码*/foo = 42;'。该声明在执行开始时发生*一次*。只有一个变量是创建的。 –