Задать вопрос
@nikolay_akhmetyanov
Front-end developer

Замыкания в чем конкретно разница?

Необходимо каждому элементу коллекции добавить обработчик.

Этот код работает
var addThumbnailClickHandler = function (thumbnail, photo) {
  thumbnail.addEventListener('click', function () {
    fullPhoto.src = photo;
  });
};

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

Этот код нет!
for (var i = 0; i < thumbnails.length; i++) {
  thumbnails[i].addEventListener('click', function () {
    fullPhoto.src = photos[i];
  });
}

Хоть убей не понимаю почему! Объясните мне пожалуйста простыми словами. Я понимаю, что здесь замыкание и тд. Я не понимаю почему второй вариант не работает, ведь есть переменная var которая увеличивается на 1, но fullPhoto.src всегда равно 5
  • Вопрос задан
  • 1000 просмотров
Подписаться 6 Простой 2 комментария
Решения вопроса 1
for (var i = 0; i < thumbnails.length; i++) {
  thumbnails[i].addEventListener('click', function () { // Корень проблемы здесь.
    // Ты обьявляешь (не вызываешь!) в цикле анонимную функцию. При создании эта функция получает
    // ссылку на внешнее лексическое окружение, которым, в данном случае, является тело цикла for.
    // Когда функция вызывается, в своем лексическом окружении i она не находит, и продолжает поиск
    // во внешнем. К моменту вызова, цикл завершен, и i в его лексическом окружении равна thumbnails.length
    fullPhoto.src = photos[i];
  });
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
dollar
@dollar
Делай добро и бросай его в воду.
Не работает, потому что к тому времени, когда функция onclick будет вызвана, переменная i дойдет до самого конца цикла. И будет использоваться именно это, последнее значение.

В первом варианте переменная i используется в конкретной итерации, т.е. берется photos[i] и это значение дальше передаётся, а сама переменная i больше не используется, так что в целом пофиг, как там она дальше будет изменяться.

Ведь в первом варианте вызов addThumbnailClickHandler(thumbnails[i], photos[i]) происходит прямо в цикле, сразу, без промедлений, а не откладывается на потом. В этот момент конкретные значения передаются в качестве параметров. И далее из-за замыкания они так и остаются висеть в памяти и ссылаться на то, что нужно.

Немного изменим код, и он снова перестанет работать :)
var i;

var addThumbnailClickHandler = function (thumbnail) {
  thumbnail.addEventListener('click', function () {
    fullPhoto.src = photos[i]; // i === thumbnails.length
  });
};

for (i = 0; i < thumbnails.length; i++) {
  addThumbnailClickHandler(thumbnails[i]);
}
Ответ написан
Комментировать
@afanasiyz
Javascript-разработчик
поменяйте var на let - это быстрое решение.

https://learn.javascript.ru/closures-usage

а вот тут, в задачках - решение вашей проблемы
Ответ написан
profesor08
@profesor08 Куратор тега JavaScript
Читай что такое var и что такое let

for (let i = 0; i < thumbnails.length; i++) {
  thumbnails[i].addEventListener('click', function () {
    fullPhoto.src = photos[i];
  });
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы