2013-10-06 2 views
1

Почему i не входит в область callback function?Переменная вне сферы применения при прослушивании слушателя событий

// All menu items collection 
var menuItems = document.getElementsByClassName('menu-item'); 

// Loop trough all menu items and attach 
// event listeners. 
for (var i = 0; i < menuItems.length; i++) { 
     // Check if element truely exsists 
     if (menuItems[i]) { 
      menuItems[i].addEventListener('click', function(e){ 
       //////////////////////////////// 
       // NOTE: i, is out of scope! // 
       ////////////////////////////// 
       var icon = menuItems[i].children[1], 
        submenu = menuItems[i].children[2]; 

       // Change icon color 
       if (icon.style.background !== "blue") { 
        icon.style.background = "blue"; 
       } else { 
        icon.style.background = "red";   
       } 

       // Show/hide submenu 
       if (submenu.style.display !== "block") { 
        submenu.style.display = "block"; 
       } else { 
        submenu.style.display = "none";   
       } 
      }); 
     } 
} 
+0

Не определено, когда событие запускается только в том случае, если установлен приемник событий? –

+0

Это вопрос ответа? – Johnny

ответ

3

Переменная i не входит в сферу применения. Просто обработчик события будет вызван через некоторое время после завершения цикла, поэтому переменная i имеет значение, которое указывает за пределами массива menuItems.

Wrap код в функции, чтобы создать область, где у вас есть копия переменной для каждой итерации:

for (var i = 0; i < menuItems.length; i++) { 
    // Check if element truely exsists 
    if (menuItems[i]) { 

    (function(i){ 

     menuItems[i].addEventListener('click', function(e){ 
     var icon = menuItems[i].children[1], 
      submenu = menuItems[i].children[2]; 

     // Change icon color 
     if (icon.style.background !== "blue") { 
      icon.style.background = "blue"; 
     } else { 
      icon.style.background = "red";   
     } 

     // Show/hide submenu 
     if (submenu.style.display !== "block") { 
      submenu.style.display = "block"; 
     } else { 
      submenu.style.display = "none";   
     } 
     }); 

    })(i); 

    } 
} 

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

Закрытие функции содержит все локальные переменные, которые функция использует из внешней области. Если menuItems - глобальная переменная, она также будет в закрытии.

+0

Javascript - это не моя сильная сторона, но не могли бы вы получить в качестве объекта события элемент меню из событий args? Разве это не устранило бы необходимость сохранения i? – Jesse

+0

Отличное объяснение, у меня есть запрос. Не могли бы вы добавить в свое представление ответа о том, как Javascript будет хранить эти два «EventListeners» по-разному как «объект». Мне бы хотелось увидеть, как Javascript хранит переменную 'i', но я хотел бы видеть ее как« объект », это очень помогло бы мне! – Johnny

+0

@Jesse: Да, поскольку переменная 'i' используется только для получения элемента, который был нажат, в этом случае он также будет работать, чтобы получить цель события. – Guffa

Смежные вопросы