为什么处理程序的上下文是窗口对象

时间:2014-06-10 13:48:30

标签: javascript

请考虑以下代码:

var myObject = {
  items : ... //some DOM elements
  ,attachHandlers: function(){
    var self = this;
    self.items.forEach(function(){
      this.addEventListener("mouseover",self.mouseOverHandler,false);
    });
  }
  ,mouseOverHandler: function(event){
      console.log(this);
  }
};

window.onload = function()
{
  myObject.attachHandlers();
}

在chrome上运行此命令,当调用mouseOverHandler时,它会打印:

Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}

我想知道,addEventListener是否将我的上下文更改为window对象?为什么这样? 我希望将事件处理程序添加到我迭代的每个元素中。

2 个答案:

答案 0 :(得分:1)

它不是jQuery,this里面Array.forEach不是你想象的那样,它是全局窗口,而第一个参数是当前迭代的元素< / p>

self.items.forEach(function (elem) {
    elem.addEventListener("mouseover", self.mouseOverHandler, false);
});

FIDDLE

此外,您可以直接将this作为参数传递给forEach并避免像这样的变量

attachHandlers: function () {
    this.items.forEach(function (elem) {
        elem.addEventListener("mouseover", this.mouseOverHandler, false);
    }, this);
},

FIDDLE

答案 1 :(得分:1)

原因与这一行有关:

this.addEventListener("mouseover",self.mouseOverHandler,false);

在该行中,this是全局对象(在浏览器上可用作window)。这就是forEach工作原理的本质:除非您指定thisArg作为forEach的第二个参数(在函数之后),否则它使用undefined。在松散模式下,这意味着在调用迭代函数期间,this是全局对象。 (在严格模式下,这意味着thisundefined。)

如果您打算将它附加到循环中的每个元素,那么:

// Accept the arg here ------v
self.items.forEach(function (element) {
    element.addEventListener("mouseover", self.mouseOverHandler, false);
//  ^--- use it here
});

然后,this中的mouseOverHandler会引用该元素,因为这是addEventListener为您提供的保证。它引用myObject。如果您希望它引用myObject对象(尽管在这种情况下没有理由),您可以使用Function#bind

,attachHandlers: function(){
  var boundHandler = this.mouseOverHandler.bind(this);
  this.items.forEach(function(element){
    element.addEventListener("mouseover",boundHandler,false);
  });
}

现在,在mouseOverHandler内,this会引用您的myObject对象(尽管在这种情况下,可能没有理由这样做)。

更多(在我的博客上)


附注:在您引用的代码中,您有addEventListner(缺少e)而不是addEventListener,我已在上面的示例中对其进行了更正。