如果推送的元素不是基元,为什么Javasctipt Array.push不使用变量

时间:2018-05-04 14:17:09

标签: javascript arrays variables for-loop closures

考虑这个经典的Javacrit闭包函数。我理解封闭是如何展示的。我理解内部函数关闭变量i,即3。

我不明白为什么数组应该包含变量i,当我们所做的就是将一个函数推入一个数组,其中我有一个来自for循环的值。

function buildFunctions() {

  var arr = [];

  for (var i = 0; i < 3; i++) {
    arr.push(function() {
      console.log(i)
    })
  }
  return arr;
}

var fs = buildFunctions(); // [function(){console.log(1)}, ...and so on]
//not [function(){console.log(i)} ...and so on]

fs[0](); // outputs 3
fs[1](); // 3
fs[2](); // 3

否则,这将返回数组的正确(imo)内容:

function buildFunctions() {
   var arr = [];
   for (var i = 0; i < 3; i++) {
      arr.push(i)
   }
   return arr; // [0, 1, 2]
 }

4 个答案:

答案 0 :(得分:3)

arr.push(i)分别将原始值传递给.push,值012。该值与此处i取消关联;你没有推i,而是推动012

arr.push(function () { console.log(i) })推送一个函数,该函数在内部引用变量。在调用函数时,该变量的值恰好是3(这是要理解的重要句子。)

请注意,推送功能和推送数字之间没有根本区别。两者都是按价值传递的。在一种情况下,值是一个数字,在另一种情况下,值是一个函数。请参阅Is JavaScript a pass-by-reference or pass-by-value language?

答案 1 :(得分:2)

我认为循环因某种原因增加了混乱。如果您展开该循环,它可能更直观。

&#13;
&#13;
function buildFunctions() {

  var arr = [];
  var i = 0;

  arr.push(function() {
    console.log(i)
  })

  i++;

  arr.push(function() {
    console.log(i)
  })

  i++;

  arr.push(function() {
    console.log(i)
  })

  i++;
  
  return arr;
}

var fs = buildFunctions(); // [function(){console.log(1)}, ...and so on]
//not [function(){console.log(i)} ...and so on]

fs[0](); // outputs 3
fs[1](); // 3
fs[2](); // 3
&#13;
&#13;
&#13;

所以你可以看到我们将三个函数推入数组,在两者之间,我们正在递增i。你还可以看到所有三个功能都是&#34;看着&#34;相同的i变量。

在调用函数之前不会读取变量 ,因为它们全部&#34;查看&#34;相同的变量,它们在最终调用时自然会产生相同的结果。由于i在任何调用之前增加了三次,因此返回的值将为3

作为练习,更改每个功能以在其中添加另一个i++。您会发现他们不仅正在阅读相同的变量,而且他们也可以改变同一个变量。

答案 2 :(得分:1)

当您调用该函数时,i的值变为3 arr.push中的函数引用。

阻止范围let将为您提供预期的结果:

&#13;
&#13;
function buildFunctions() {

   var arr = [];

   for (let i = 0; i < 3; i++) { 
       arr.push(function() { 
          console.log(i)
       }) 
   }
   return arr;
}

var fs = buildFunctions(); // [function(){console.log(1)}, ...and so on]
                           //not [function(){console.log(i)} ...and so on]

fs[0](); // 0
fs[1](); // 1
fs[2](); // 2
&#13;
&#13;
&#13;

答案 3 :(得分:1)

  

我不明白为什么数组应该包含变量i

它没有。

该数组包含三个函数。

每个函数都关闭(相同)变量i。注意:i当时不是 i 的值。

调用任何函数(循环完成后 )时,它们会读取该变量的值。