【问题标题】:Javascript "this" overridden by event listener [duplicate]事件侦听器覆盖的Javascript“this”[重复]
【发布时间】:2013-05-11 23:18:28
【问题描述】:

我可能做错了什么,但在尝试将一些面向对象编程应用于 Javascript 时,我发现了一些有趣的行为。考虑以下

function Bug(element) {
    this.focusedCell = null;
    element.addEventListener('click', this.onClick, true);
};

Bug.prototype.onClick = function(event){
    console.log("this is: ");
    console.log(this);
};

当我从控制台调用该方法时,我看到了正确的“this”实例,但是当我单击文档中的元素时,我看到的是文档元素代替了该实例。所以......可能将事件侦听器与实例方法一起使用可能不是一个好主意,至少我这样做的方式是这样。

所以问题是:

  • 是否可以有这样的事件监听器,它调用 javascript 对象的实例方法,同时保留调用中的实例?

  • 这样做有更好的模式吗?

编辑: 除了 Chrome 之外,我还没有尝试过这个。但我想行为是一样的。

【问题讨论】:

  • 函数创建一个新的作用域。
  • 谢谢,抱歉不知道这是重复搜索,没有显示任何内容。
  • @FelixKling 哇,亲爱的,你找到了一个完美的伴侣..
  • 实际上有很多重复,但它们的标题可能很奇怪。
  • 我也googled 了,不过没关系。我在 SO 上搜索了“覆盖这个”,但没有找到。我不知道它与覆盖的事件侦听器明确相关。

标签: javascript oop events


【解决方案1】:

有一个更好的模式,不需要太多的改变。我先展示代码。

function Bug(element) {
    this.focusedCell = null;
    // --------------------------------v----pass the object, not a function
    element.addEventListener('click', this, true);
};

// Implement the `EventListener` interface
Bug.prototype.handleEvent = function(event) {
    if (event.type === "click")
        this.onClick(event);
}

Bug.prototype.onClick = function(event) {
    console.log(JSON.stringify(this));         // '{"focusedCell":null}'
    console.log(event.currentTarget.nodeName); // "DIV"
};

通过添加handleEvent 方法,我们使Bug 实现EventListener 接口。这允许我们将新的 Bug 对象作为第二个参数传递给 addEventListener() 而不是函数。

现在当"click"事件发生时,.handleEvent()方法将被调用,该方法中this的值将是绑定的Bug对象。


由于this 是对Bug 实例的引用,它显然不再是对元素的引用。但这不是必需的,因为该元素可通过 event.currentTarget 获得。

当然,如果需要,您可以将元素直接添加到构造函数中的 Bug 对象中。

演示: http://jsfiddle.net/CnZTa/


【讨论】:

  • @lukecampbell:如果您有很多其他事件类型,请考虑在事件之后命名您的方法。然后你的handleEvent() 方法可以简单地做return this[event.type] && this[event.type](event);
  • 我希望我能不止一次地眯着眼睛投票。
  • The code here 可用于提供与旧版浏览器的兼容性。
  • @squint hehe,我想一旦 Harmony 加入,你会学到更多东西 ;)
  • 我猜有人不喜欢(或者更可能理解)这个解决方案?如果您不熟悉此技术,请务必询问。我很乐意解释更多。
【解决方案2】:

您可以使用Function.prototype.bind 创建一个绑定到您想要的任何this 值的侦听器:

function Bug(element) {
    this.focusedCell = null;
    element.addEventListener('click', this.onClick.bind(this), true);
};

较旧的(非 ES5)浏览器将需要一个 polyfill,例如来自 MDN 的那个。

【讨论】:

    【解决方案3】:

    这是 JavaScript 中的正常行为。您可以通过向侦听器传递一个函数来保留您预期的this

    function Bug(element) {
        var self = this; // Store a reference to this
        this.focusedCell = null;
        element.addEventListener('click', function() {
            // in here this refers to element
            self.onClick(event);
        }, true);
    };
    
    Bug.prototype.onClick = function(event){
        console.log("this is: "); 
        console.log(this); // In here this refers the an instance of Bug.
    };
    

    【讨论】:

    • 代码是对的,但是解释不是很清楚。 "by passing a function to the listener"... 这就是 OP 已经做的事情。不同之处在于该函数在您的情况下是内联定义的,因此它在父函数的范围内创建了一个闭包,允许从处理函数访问 self 变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    相关资源
    最近更新 更多