@MdaUZH

Почему странно работает цикл?

Всем привет, столкнулся с проблемой, раньше все подобное работало.

есть код:
<div class="a">...</div>
<div class="a">...</div>
<div class="a">...</div>

<div class="b">...</div>
<div class="b">...</div>
<div class="b">...</div>


И JS
var _a = document.querySelectorAll('.a'),
      _b = document.querySelectorAll('.b');

for(var i = 0; i < _a.length; i++){
      _a[i].addEventListener('click', function(){console.log( _b[i] ); },false);
      _b[i].addEventListener('click', function(){console.log( _a[i] ); },false);
}

Это как пример, на деле схожий вариант.

Собственно не работает, по клику ругается, говорит что элемент _a (или _b) - undefined

делаю console.log(_a) - все элементы есть, индексы есть, все есть.

Но не работает...

Делаю так:
var _a = document.querySelectorAll('.a'),
      _b = document.querySelectorAll('.b');

      _a[0].addEvent...
      _b[0].addEvent...

      _a[1].addEvent...
      _b[1].addEvent...

      _a[2].addEvent...
      _b[2].addEvent...


И так все работает, в чем может быть причина?
Сижу часа 2 уже, понять никак не могу, в ручную расставил индексы, а в чем проблема понять не могу :c

Количество _a элементов всегда равно количеству _b (не может быть что _а - 3, а _b - 2)

Всем заранее спасибо
  • Вопрос задан
  • 286 просмотров
Решения вопроса 1
AngReload
@AngReload
Кратко о себе
Всё объясню:
Как работает код:
Находятся элементы на странице и помещаются в массив x = [0, 1, 2];
Начинается цикл объявлением глобальной переменной i = 0;
Затем идет проверка, и если i < длины массива, то:
1) на div вешается функция слушатель для нажатия с функцией function(){console.log( _x[i] )
2) глобальная переменная i увеличивается на единицу.
Когда i достигает значения больше индексов массива (i = 3, не проходит проверку) цикл прекращается.

Теперь мы наводим курсор на div и кликаем:
Слушатель запускает функцию function(){console.log( _x[i] )
Функция пытается найти i.
Так как внутри функции переменная i не была определена, она обращается к глобальной области видимости.
В глобальной области видимости переменная i == 3, по такому индексу в массиве ничего нет - функция пишет в консоль undefined.

Как исправить:
Создать функцию, которая будет создавать функции с определенным индексом и вызывать её в цикле:
var _a = document.querySelectorAll('.a'),
      _b = document.querySelectorAll('.b');

function f_console_log_B_for_index(i) {
      return function(){console.log( _b[i] );}
}
function f_console_log_A_for_index(i) {
      return function(){console.log( _a[i] );}
}
for(var i = 0; i < _a.length; i++){
      _a[i].addEventListener('click', f_console_log_A_for_index(i),false);
      _b[i].addEventListener('click', f_console_log_B_for_index(i),false);
}

В такой создаваемой функции значение переменной i будет таким с каким вызвали функцию, создавшую её.
Прочитайте про области видимости и замыкания.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
HalfBloodPrince
@HalfBloodPrince
Front-End Developer
Думаю, не стоит определять функцию во время цикла. Так должно сработать.
var _a = document.querySelectorAll('.a'),
      _b = document.querySelectorAll('.b');

function cc(a) {
  console.log(a);
}

for(var i = 0; i < _a.length; i++){
      _a[i].addEventListener('click', cc(_b[i]),false);
      _b[i].addEventListener('click', cc(_b[i]), false);
}
Ответ написан
Комментировать
@lem_prod
var _a = document.querySelectorAll('.a'),
      _b = document.querySelectorAll('.b');

for(var i = 0; i < _a.length; i++){
      _a[i].addEventListener('click', function(){console.log( _b[i] ); },false);
      _b[i].addEventListener('click', function(){console.log( _a[i] ); },false);
}


цикл идет 0 -> true, 1 - > true ... 3 - false( 3 < 3), потом когда вызывается функция console.log( _a[i]) оно ищет "i", находит собственно 3, а _a[3] у нас нет, только _а[0], _а[1], _а[2]

обратите внимание, что вы добавляете НЕ:
function(){console.log( _b[0] )
function(){console.log( _b[1] )
function(){console.log( _b[2] )


а:
function(){console.log( _b[i] )
function(){console.log( _b[i] )
function(){console.log( _b[i] )


и эту "i" оно ищет потом, при вызове.

Отвечаю на комментарий, для примера вот код:

var l = 3;
for (var i = 0, i < l; i = i + 1) {
console.log(i); //0, 1, 2
}

console.log('после цикла:' + i); //3


лучше всего запустите отладчик в консоле, и проследите все это...
происходит следующее, первый заход "и" , "и" меньше "л"(правда), увеличивается "и" на одни, но в скобки попадает старое значение....как то так если на пальцах...
тоесть, когда у вас выполняется 3 раз("и" == 2), оно увеличивает "и" на 1, то есть "и" == 3, но когда инструкция "и" меньше "л" не сработает, цикл дальше не пойдет, но и уже увеличена, потому что прибавление произошло в конце прошлого цикла.
Ответ написан
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы