Почему Javascript работает таким образом? - PullRequest
1 голос
/ 25 марта 2020

Итак, я увидел чей-то твит в Твиттере, упомянув, что во время собеседования на работу был дан следующий сценарий.

for (var i = 0; i < 3; i+=1) {
    setTimeout(function() {
        console.log(i)
    }, 100)
}

Респонденту было предложено предсказать исход этого сценария, и он упомянул, что он очевиден для его в своем твите.

Для меня, как совершенно нового (или не заинтересованного) в Javascript, трудно понять, почему результат не является одним из:

1) 0, 1 , 2 последовательно. (как традиционное «для-l oop»)

2). печать 3 только один раз. (Если итерация полностью выполнена до вызова функции)

, но трижды печатать 3.

Это потому, что Javascript не является последовательным языком программирования или характеристиками c из Javascript или оба?

Ответы [ 3 ]

7 голосов
/ 25 марта 2020

Чтобы понять это, вам нужно понять, как JavaScript основан на событиях и как работают области, поэтому, я полагаю, он используется в качестве вопроса для интервью.

В основном, JavaScript основан на очереди событий. В приведенном примере кода setTimeout не выполняет код немедленно, но сообщает движку, что код должен сработать за 100 мс.

Однако for l oop выполняется немедленно , Само по себе это не будет проблемой, если вы используете определение переменной области блока, например let i = 0. Например, следующий код напечатает 0, 1, 2:

for (let i = 0; i < 3; i+=1) {
    setTimeout(function() {
        console.log(i)
    }, 100)
}

Однако в коде используется var, который «поднимается» в начало определения функции, или в этом случай, верхняя часть фрагмента / файла. Таким образом, на самом деле код должен выглядеть следующим образом:

var i;
for (i = 0; i < 3; i+=1) {
    setTimeout(function() {
        console.log(i)
    }, 100)
}

Это имеет интересный эффект: теперь for l oop выполняется три раза, увеличивая i до значения 3. Затем после завершения выполнения for l oop вызывается функция обратного вызова setTimeout, которая имеет то же значение i в своей области видимости (потому что она была поднята). Вот почему он печатает 3 три раза.

2 голосов
/ 25 марта 2020

Это потому, что когда вы объявляете переменную с ключевым словом var , вы объявляете глобальную (в данном случае) переменную. А теперь рассмотрим для l oop как задачу для выполнения. setTimeout добавляет еще одну задачу для выполнения, но после завершения для l oop. Таким образом, порядок выполнения:

  1. Повторение 3 раза с для l oop. И увеличиваем i переменную 3 раза.
  2. Log i переменную 3 раза, потому что вы вызывали setTimeout 3 раза.

Если вы хотите узнать больше об этом, вот отличная статья: https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

Но когда вы объявляете i переменную с let ключевое слово, это локальная переменная. Его объем - одна итерация для l oop. Таким образом, для каждой отдельной итерации существует отдельная переменная (она не перезаписывается следующей итерацией),

1 голос
/ 25 марта 2020

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

l oop будет выполнен 3 раза и для переменной i будет установлено значение 3, и больше не будет изменяться.

Метод setTimeout будет вызывать обратный вызов, переданный в качестве первого параметра через 0,1 секунды, когда значение i уже установлено в 3, поэтому он будет постоянно отображать 3 в console.log как значение i во время выполнения обратного вызова.

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