为什么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 :(得分:4)
变量i
不在范围之外。只是在循环完成后的某个时间调用事件处理程序,因此变量i
的值指向menuItems
数组之外。
将代码包装在函数中,以创建一个范围,其中每个迭代都有一个变量的副本:
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
是全局变量,否则它也将在闭包中。