IIFE和Javascript中的变量赋值。我们真的需要IIFE吗?到底是怎么回事?

时间:2016-12-15 16:45:49

标签: javascript

说我有这个功能:

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

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

所以这会返回未定义的3次。

我可以在很高的层次上看到,由于变量不是按值存储而是通过引用封闭内部...循环首先完成,并且当函数从事件循环中出列时...变量已经是未定义的(fruits.length计算结果为3,这对于此数组大小来说太高了)。但是为什么这会表现得很奇怪...它会打印出#34; apple&#34; 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需要解决这个问题?

3 个答案:

答案 0 :(得分:3)

第二个例子

&#13;
&#13;
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"])
&#13;
&#13;
&#13;

这会记录三次芒果。因为每次创建someConstant变量并重新初始化为i。重新收集循环的工作原理。 i值在此增加到4,检查条件4 <3,并终止。所以循环内部的事情只执行三次。因此,printFruits功能范围中定义的someConstant的最后一个值是2.所以当内部函数执行someConstant时,它等于2.所以我们每次都得到Mango。

第3个例子

&#13;
&#13;
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"])
&#13;
&#13;
&#13;

这里发生了关闭之美。这是一个立即执行的自执行功能。所以当i = 1时,它会立即调用。现在每个功能都有不同的范围。每个都定义了一个单独的当前值。所以稍后当它执行时,它会回想出当前&#39;当前的价值。当它在其范围内定义时。

答案 1 :(得分:2)

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

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

答案 2 :(得分:1)

不同之处在于someConstant在最后一次迭代后永远不会增加。 for()循环设置i = 3,测试i < fruits.length失败,因此循环停止。因此,someConstant仍然从循环的最后一次迭代设置为2。然后所有回调都会运行,因此它们都会记录fruits[2] Mango

你需要IIFE让每次迭代在闭包中保存i的值。