2

为什么在此代码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";         
                }
            });
        }
}
4

1 回答 1

5

变量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是全局变量,否则它也会在闭包中。

于 2013-10-06T00:12:41.747 回答