【问题标题】:Scope of an anonymous function as an argument [duplicate]作为参数的匿名函数的范围[重复]
【发布时间】:2017-05-09 08:48:47
【问题描述】:

我正在开发一个非常简单的应用程序。当用户将鼠标悬停在任何列表项 (li) 上时,文本颜色变为绿色,当鼠标离开时,文本颜色变为黑色。

为什么我们不能在匿名函数的下面这段代码中使用lis[i] 而不是this 关键字?

var lis = document.querySelectorAll('li');
var i = 0;
for(; i < lis.length; i++){

    lis[i].addEventListener('mouseover', function(){

    this.style.color = 'green';

    });
    lis[i].addEventListener('mouseout', function(){

    this.style.color ="black";  
    });
};

【问题讨论】:

    标签: javascript html css this anonymous-function


    【解决方案1】:

    当回调函数将被执行时,i 变量会因为循环而具有lis.length 的值,导致lis[i] 的值是undefined

    您可以做的是改用forEach 函数。

    var lis = document.querySelectorAll('li');
    lis.forEach(function (li) {
      li.addEventListener('mouseover', function (){
        li.style.color = 'green';
      });
      li.addEventListener('mouseout', function (){
        li.style.color ="black";  
      });
    });
    <ul>
      <li>First LI</li>
      <li>Second LI</li>
    </ul>

    【讨论】:

    • 实际上,i 仍将被定义,但停留在 for 循环的最后一个值上(在本例中为 lis.length,使 lis[i] 未定义)。这是由于 Javascript 闭包造成的。请参阅@Duncan 的回答。
    • @MichaelYang 感谢您指出,我更关注解决方案而不是问题的根源
    • 当然——您的解决方案非常好!我只是想指出这一点:-)
    【解决方案2】:

    在调用函数时,循环已经完成。只有一个i 变量,函数总是看到它的当前值。所以如果你在函数内部使用i,你会看到它的值是lis.length

    有很多方法可以解决它。如果你可以使用 ES2015(可能通过转译器),那么你可以这样写:

    const lis = document.querySelectorAll('li');
    for(let i = 0; i < lis.length; i++){
    
        lis[i].addEventListener('mouseover', () => lis[i].style.color = 'green');
        lis[i].addEventListener('mouseout', () => lis[i].style.color ="black");
    };
    

    现在您在循环中的每次都有不同的i

    或者在旧代码中,您可以将循环体推送到另一个函数并将i 作为参数传入。这具有为每个事件绑定不同变量的相同效果:

    var lis = document.querySelectorAll('li');
    
    var _loop = function _loop(i) {
    
        lis[i].addEventListener('mouseover', function () {
            return lis[i].style.color = 'green';
        });
        lis[i].addEventListener('mouseout', function () {
            return lis[i].style.color = "black";
        });
    };
    
    for (var i = 0; i < lis.length; i++) {
        _loop(i);
    }
    

    (这是我上面给出的 ES2015 示例中 babel 自动生成的代码)

    【讨论】:

      【解决方案3】:

      你可以像这样使用“e.srcElement”来获取当前目标

      let lis = document.querySelectorAll('li');
      
      for (let i = 0; i < lis.length; i++) {
        lis[i].addEventListener('mouseover', function(e){
          e.srcElement.style.color = 'green';
        })
        lis[i].addEventListener('mouseout', function(e){
          e.srcElement.style.color = 'black';
        })
      }
      <ul>
        <li>First LI</li>
        <li>Second LI</li>
      </ul>

      【讨论】:

      • 他们可以,但这与他们提出的问题无关
      猜你喜欢
      • 1970-01-01
      • 2013-06-25
      • 2011-02-13
      • 1970-01-01
      • 1970-01-01
      • 2018-08-16
      • 2012-05-25
      • 1970-01-01
      • 2012-10-12
      相关资源
      最近更新 更多