简体   繁体   English

如果被推送的元素不是原始元素,为什么JavaScript Array.push不使用变量

[英]Why does JavaScript Array.push not use variable if the pushed element is not a primitive

Consider this classic JavaScript closure function. 考虑这个经典的JavaScript闭包功能。 I understand how the closure is exhibited. 我了解封包的展示方式。 I understand that the inner function closes in on the variable i, which is 3. 我知道内部函数会关闭变量i,即3。

What I dont understand is why the array should contain the variable i, when all we are doing is pushing a function into an array where i has a value from the for loop. 我不明白的是为什么数组应该包含变量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 

otherwise, this would return the correct(imo) contents of the array: 否则,这将返回数组的正确(imo)内容:

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

arr.push(i) passes a primitive value to .push , the values 0 , 1 and 2 respectively. arr.push(i)通过一个原始值到.push ,值012分别。 The value becomes disassociated from i here; 这里的值与i解除关联; you're not pushing i , you're pushing 0 , 1 and 2 . 你不推i ,你推012

arr.push(function () { console.log(i) }) pushes a function, which internally references a variable. arr.push(function () { console.log(i) })推送一个内部引用变量的函数。 At the time that you call the function, the value of that variable happens to be 3 . 在调用函数时,该变量的值恰好是3 (👈 This is the critical sentence to understand.) (👈这是要理解的关键句子。)

Note that there's no fundamental difference between pushing a function and pushing a number. 请注意,推函数和推数字之间没有根本区别。 Both are simply passed by value. 两者都简单地通过值传递。 Just in one case the value is a number and in the other case the value is a function. 在一种情况下,值是一个数字,在另一种情况下,值是一个函数。 See Is JavaScript a pass-by-reference or pass-by-value language? 请参阅JavaScript是引用传递还是值传递语言? .

I think the loop adds confusion for some reason. 我认为循环由于某种原因而增加了混乱。 If you unroll that loop, it likely is more intuitive. 如果展开该循环,则可能更直观。

 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 

So you can see that we're pushing three functions into the array, and in between, we're incrementing i . 因此,您可以看到我们正在将三个函数推入数组,而在两者之间,我们正在递增i You can also see that all three functions are "looking at" the same i variable. 您还可以看到所有三个函数都在“看”相同的i变量。

The variable is not read until the function is invoked , so because they're all "looking at" the same variable, they're naturally going to give the same result when finally invoked. 调用函数之前,不会读取变量,因此,由于它们都在“看”相同的变量,因此最终调用它们时,它们自然会给出相同的结果。 And because the i was incremented three times before any of the invocations , the value returned will be 3 . 而且由于在任何一次调用之前 i都增加了3倍,因此返回的值为3


As an exercise, change each function to add another i++ within. 作为练习,更改每个函数以在其中添加另一个i++ You'll see that no only are they all reading the same variable, but they all can mutate that same variable too. 您将看到,不仅它们都读取同一个变量,而且它们都可以突变相同的变量。

By the time you call the function the value of i becomes 3 which the function inside arr.push refer. 当您调用该函数时, i的值将变为3 ,这是arr.push内部的函数arr.push引用的。

Block scope let will give you the expected result: 块范围let将给您预期的结果:

 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 

What I dont understand is why the array should contain the variable i 我不明白的是为什么数组应该包含变量i

It doesn't. 没有。

The array contains three functions. 该数组包含三个函数。

Each of those functions closes over the (same) variable i . 这些函数中的每一个都关闭(相同)变量i Note: i not the value of i at the time. 注: i没有价值i的时间。

When you call any of the functions (which is after the loop has finished ), they read the value of that variable. 您调用任何一个函数( 在循环完成之后 )时,它们都会读取该变量的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM