Знакомство с событиями 22/25

Непонятно как работает цикл в этом коде:

var photos = [
  'gallery/laptop-large.jpg',
  'gallery/microphone-large.jpg',
  'gallery/keyboard-large.jpg',
  'gallery/signboard-large.jpg',
  'gallery/tree-large.jpg'
];


var thumbnails = document.querySelectorAll('.gallery__photo-preview');
var fullPhoto = document.querySelector('.full-photo');

var addThumbnailClickHandler = function (thumbnail, photo) {
  thumbnail.addEventListener('click', function () {
    console.log(thumbnail);
    console.log(photo);
  });
};

for (var i = 0; i < thumbnails.length; i++) {
  addThumbnailClickHandler(thumbnails[i], photos[i]);
}

Страница загрузилась, все скрипты отработали и цикл в том числе.
И в результате к моменту когда пользователь кликнет на кнопку в цикле уже все равно i = 5.
Т.е. вот так:
for (var i = 0; i < thumbnails.length; i++) {
addThumbnailClickHandler(thumbnails[5], photos[5]);
}
И хоть как там обкликайся, в функцию все равно будут передаваться параметры с i = 5.

Или цикл начинает работать не сразу после загрузки страницы?

Еще раз перепрошел задания с 12 по 22.
Понял только, что это как-то связано с замыканием.
Но все равно не понятно в деталях.

Мы вставили функцию обработчик клика во внешнюю функцию, в которую передаём данные.
Во внешнюю функцию мы передали ВСЕ значения thumbnails[i], photos[i] из цикла ниже.
Получается в локальной области видимости (созданной внешней функцией) хранится не ОДНО значение переменной а ВСЕ значения которые есть в коллекции и в массиве (которые были переданы ей в результате работы цикла ниже).
И в нужный момент функция обработчик берёт одно из них, по которому произошел клик, я правильно понял???

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

Допустим, у нас есть код:

for (var i = 0; i < thumbnails.length; i++) {
  thumbnails[i].addEventListener('click', function () {
    fullPhoto.src = photos[i];
  });
}

В этом коде создается пять обработчиков событий. То есть, пять функций.
У каждой функции есть скрытое свойство, которое хранит ссылку на ту область видимости, где она была создана. Т.е. при выполнении этой функции браузер увидит следующее: “узнай значение i в таком-то месте”. В данном случае - из внешней переменной i.

К тому моменту, как ты нажмешь на картинку и событие вызовется, цикл уже давно отработает. И в переменной i будет храниться число 5. Поэтому любой обработчик событий, когда обратится к переменной i, получит именно число 5.

Поэтому надо сделать так, чтобы обработчик лез не за этой общей переменной i, а хранил ее копию. Чтобы на первой итерации цикла первый обработчик сохранял 0, второй обработчик - 1, и так далее.

Сейчас это решено через let. Просто пишите цикл с let, и на каждой итерации цикла будет создаваться новая копия этой переменной. Т.е. если у вас цикл проходит 10 итераций, то и будет создано 10 “разных” переменных i. А в случае с var - она одна, общая.

Здесь это реализовано через внешнюю функцию. На каждой итерации вызывается функция addThumbnailClickHandler(thumbnails[i], photos[i]);. И каждый раз в памяти сохраняется новая область видимости функции. У вас будет функция-1 addThumbnailClickHandler со значением 0 внутри. Функция-2 addThumbnailClickHandler со значением 1, и так далее. Сколько раз вы вызовете одну и ту же функцию, столько ее копий и будет храниться в памяти. Пока на них есть ссылка, конечно.

Так работают и замыкания. Из некоторой функции outerF() мы возвращаем функцию innerF():

function outerF() {
  let a = 10;
  
  function innerF() {
    console.log(a);
  }
  
  return innerF;
}

let closure = outerF();

outerF() выполняется, возвращает innerF(), и эта функция сохраняется в переменную closure. И вот эта innerF() хранит в себе ссылку на область видимости outerF() с ее всеми значениями. В данном случае она имеет доступ к переменной a. И мы тоже имеем к ней доступ через closure. Вызовем closure() - выполнится та самая innerF(), которая обратится к переменной a из outerF(). Причем вызвать closure() мы можем когда угодно.

2 лайка