2

При клике на какой либо из item'ов цикл уже пройден, то есть i == 4. Кто может на пальцах объяснить.

var items = document.querySelectorAll('.item');

for(var i = 0; i < items.length; i++) { items[i].addEventListener('click', function() { alert(i); }); }

.items {
    display: flex;
}

.item {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 200px;
    height: 200px;
    margin: 15px;
    background: #ccc;
    cursor: pointer;
    user-select: none;
}

.active {
    background: #aaa;
}
<div class="items">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>
  • 1
    Типичный вопрос на всех собеседованиях. Погуглите про замыкание – ThisMan Aug 27 '18 at 11:24
  • при добавлении слушателя событий никакое событие не происходит, но если передать значение обработчику события то тогда он будет выводить его когда событие произойдет. То есть цикл прокручивается, а переменная тоже прокручивается вместе с циклом. – Roman C Aug 27 '18 at 11:34

1 Answers1

4

В функцию обработчика события клика вы передаете одну и ту же переменную, не ее значение! А так как вы нажимаете на элемент после цикла, то выводится ее конечное значение(4). Самый простой способ решить проблему - в цикле заменить var на let, при этом решении для каждой итерации(шаг цикла) будет создана своя локальная переменная i.

Вчера отвечал на этот вопрос.

var items = document.querySelectorAll('.item');

for(let i = 0; i < items.length; i++) { items[i].addEventListener('click', function() { alert(i); }); }

.items {
    display: flex;
}

.item {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 200px;
    height: 200px;
    margin: 15px;
    background: #ccc;
    cursor: pointer;
    user-select: none;
}

.active {
    background: #aaa;
}
<div class="items">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
</div>

Есть более старое решение: тут же вызвать ф-ю обертку с локальной переменной которая возвращает ф-ю которая уже будет участвовать в обработке события.

items[i].addEventListener('click', 
  (function (localI) {
      return function (event) { alert(localI) };
  }(i))
);