Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 01.09.2019, 22:50
Интересующийся
Отправить личное сообщение для Devero97 Посмотреть профиль Найти все сообщения от Devero97
 
Регистрация: 03.08.2019
Сообщений: 17

Замыкания в цикле
Здравствуйте. Помогите разобраться с такой проблемой. Есть код:

for(var i = 0; i <= 5; i++){
 setTimeout () {function(){
  console.log(i)
 }, i*1000}
}


1. Почему когда происходит выполнение кода, в консоль записывается 5 шестерок, а тайм-аут срабатывает именно каждую секунду? Тут вопрос не про вывод на консоль шетерок, а именно работа тайм-аута. Каким образом секунда увеличивается постепенно, если логически, после выполнения цикла, вместо i * 1000 должно подставиться 6 * 1000?

Следующий код:

for(var i = 0; i <= 5; i++){
 (function(){
   var j = i;
   setTimeout () {function(){
    console.log(j)
   }, j*1000}
  }())
}


2. Почему при таком варианте, каким-то образом каждая итерация запоминается в переменную j? Я понимаю что это замыкание и тайм-аут видит по замыканию сохраненной значение в переменной j каждый раз. Но вот как это происходит? Вот цикл завершился и записал в j шестерку. А как тайм-аут запомнил, что там были числа 0,1 и т.д.?
Или тут работает отложенный вызов или какой-то стек создается? Тоесть сначало в j присваивается 0 а затем подставляется в тайм-аут функцию и она выполняется и так далее. Но ведь цикл завершается гораздо быстрее чем 1 секунда.
Помогите разобраться.
Ответить с цитированием
  #2 (permalink)  
Старый 01.09.2019, 22:56
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,064

Сообщение от Devero97
Почему когда происходит выполнение кода, в консоль записывается 5 шестерок,
лечится заменой var на let,
потому что переменная i одна на весь код, и каждом таймере одна и таже, со значением на момент окончания for
Сообщение от Devero97
Почему при таком варианте, каким-то образом каждая итерация запоминается в переменную j?
потому что переменная j, всякий раз новая и у каждого таймера своя.
Ответить с цитированием
  #3 (permalink)  
Старый 01.09.2019, 23:22
Интересующийся
Отправить личное сообщение для Devero97 Посмотреть профиль Найти все сообщения от Devero97
 
Регистрация: 03.08.2019
Сообщений: 17

Сообщение от рони
лечится заменой var на let,
Я про это знаю, мне интересно как работает с переменной var.
Сообщение от рони
потому что переменная i одна на весь код, и каждом таймере одна и таже, со значением на момент окончания for
Как тогда код работает? В цикле 0 меньше 5, значение увеличивается и 1 подставляется в i * 1000, но не успевает попасть во внутрь кода анонимной функции тайм-аута? Цикл уже как-то завершился и туда попала шестерка. Может сможете привести пример проще?
Сообщение от рони
потому что переменная j, всякий раз новая и у каждого таймера своя.
Почему она всегда новая? Разве туда не сохраняется значения выполненного цикла? А именно 6?
Ответить с цитированием
  #4 (permalink)  
Старый 01.09.2019, 23:56
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,064

Сообщение от Devero97
Почему она всегда новая? Разве туда не сохраняется значения выполненного цикла? А именно 6?
потому что функция в строке 2 получила данные и отработала, никаких новых данных в неё не поступит.
var j = i; j получила значение(число в данном случае) переменной i, но знать не знает о переменной i.

в первом варианте идет ссылка на саму переменную, а не на её значение, какое значение имеет i на момент вывода консоли, то и покажет.
может чем поможет, Пример ошибочного использования
Ответить с цитированием
  #5 (permalink)  
Старый 02.09.2019, 10:12
Профессор
Отправить личное сообщение для Rise Посмотреть профиль Найти все сообщения от Rise
 
Регистрация: 07.11.2013
Сообщений: 4,662

Сообщение от Devero97
Есть код:
И он неправильный, правильно так:
for(var i = 0; i <= 5; i++){
    setTimeout(function() { console.log(i) }, i * 1000);
}

Сообщение от Devero97
А как тайм-аут запомнил, что там были числа 0,1 и т.д.?
Тайм-аут ничего не запоминает, запоминает функция, которая создана и передана ему аргументом function() { console.log(i) }. Функции запоминают переменные окружения в месте своего создания, а не в месте своего вызова. Тайм-аут когда-то потом ее вызовет, но это уже не важно.

Последний раз редактировалось Rise, 02.09.2019 в 10:16.
Ответить с цитированием
  #6 (permalink)  
Старый 02.09.2019, 10:33
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,064

Сообщение от Rise
И он неправильный, правильно так:
может забыли аргумент добавить???
Ответить с цитированием
  #7 (permalink)  
Старый 02.09.2019, 10:37
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,004

я на собеседованиях люблю "охладить пыл" собеседующих вот таким вариантом
for(var i = 0; i <= 5; i++){
    setTimeout(function(i) { console.log(i) }, i * 1000, i);
}
Ответить с цитированием
  #8 (permalink)  
Старый 02.09.2019, 12:21
Аватар для SuperZen
Профессор
Отправить личное сообщение для SuperZen Посмотреть профиль Найти все сообщения от SuperZen
 
Регистрация: 08.11.2017
Сообщений: 642

let v = 4 // примитив
let w = { v: 4 } // объект
function a(v) { // v передается значением
  return {
    b: function () {
      console.log('b', v++) //4
      return this
    },
    c: function () {
      this.b() //5
      return this
    },
    d: function (w) { // w передается ссылкой
      console.log('d', w.v++) // 4
    }
  }
}
a(v).b().c().d(w)
console.log('-', v) // 4
console.log(w) // { v: 5 }


наверное, стоит рассмотреть и такой пример )
Ответить с цитированием
  #9 (permalink)  
Старый 02.09.2019, 12:32
Аватар для Alexandroppolus
Профессор
Отправить личное сообщение для Alexandroppolus Посмотреть профиль Найти все сообщения от Alexandroppolus
 
Регистрация: 25.10.2016
Сообщений: 1,004

Сообщение от SuperZen
w передается ссылкой
w тоже передается значением.
просто это сама по себе ссылка на объект, потому внутри объекта можем что-то менять

но сделав, например, w = null внутри метода, мы не поменяем внешнюю w. Потому что она была передана по значению
Ответить с цитированием
  #10 (permalink)  
Старый 02.09.2019, 12:43
Аватар для SuperZen
Профессор
Отправить личное сообщение для SuperZen Посмотреть профиль Найти все сообщения от SuperZen
 
Регистрация: 08.11.2017
Сообщений: 642

Alexandroppolus, хорошее замечание )
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Навешивать события в цикле Neo54213 Events/DOM/Window 3 01.08.2017 09:46
замыкания и утечки памяти newobject Общие вопросы Javascript 1 18.07.2014 12:39
Таймер до требуемой даты в цикле Drugpunker Events/DOM/Window 22 21.03.2014 08:52
popup окно в PHP цикле ryobi522 Общие вопросы Javascript 5 10.02.2012 02:18
Про замыкания Иваннн Общие вопросы Javascript 3 12.01.2011 11:12