Почему Javasctipt Array.push не использует переменную, если помещенный элемент не является примитивом - PullRequest
0 голосов
/ 04 мая 2018

Рассмотрим эту классическую функцию закрытия 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 голосов
/ 04 мая 2018

Я думаю, что цикл добавляет путаницу по какой-то причине. Если вы развернете этот цикл, он, вероятно, станет более интуитивным.

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

Итак, вы можете видеть, что мы помещаем три функции в массив, а между ними мы увеличиваем i. Вы также можете видеть, что все три функции «смотрят» на одну и ту же переменную i.

Переменная не читается до тех пор, пока функция не будет вызвана , поэтому, поскольку все они "смотрят" на одну и ту же переменную, они, естественно, будут давать один и тот же результат при окончательном вызове. И поскольку i был увеличен в три раза перед любым из вызовов , возвращаемое значение будет 3.


В качестве упражнения измените каждую функцию, чтобы добавить еще i++. Вы увидите, что они не только читают одну и ту же переменную, но все они могут видоизменить эту же переменную.

0 голосов
/ 04 мая 2018

К тому времени, когда вы вызываете функцию, значение i становится 3, к которому относится функция внутри arr.push.

Область действия блока 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
0 голосов
/ 04 мая 2018

Я не понимаю, почему массив должен содержать переменную i

Это не так.

Массив содержит три функции.

Каждая из этих функций закрывается над (той же) переменной i. Примечание: i не значение i в то время.

Когда вы вызываете любую из функций (то есть после завершения цикла ), они считывают значение этой переменной.

0 голосов
/ 04 мая 2018

arr.push(i) передает примитивное значение в .push, значения 0, 1 и 2 соответственно. Значение становится диссоциированным от i здесь; вы не нажимаете i, вы нажимаете 0, 1 и 2.

arr.push(function () { console.log(i) }) выдвигает функцию, которая внутренне ссылается на переменную. В тот момент, когда вы вызываете функцию, значение этой переменной составляет 3. (? Это критическое предложение для понимания.)

Обратите внимание, что нет принципиальной разницы между нажатием функции и нажатием числа. Оба просто передаются по значению. Просто в одном случае значение является числом, а в другом случае значение является функцией. См. Является ли JavaScript языком передачи по ссылке или передачей по значению? .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...