JavaScript PubSub 模式:"this" 的上下文发生了什么,为什么会丢失?

JavaScript PubSub Pattern: What is happening with the context of "this", why is it lost?

我开始尝试使用 JavaScript 中的 publish/subscribe 模式,但现在遇到了一个我不明白的问题。

采用以下场景:

单击按钮时,会发出一条消息,这有效。

document.getElementById('myBtn').addEventListener('click', function() {
    PubSub.publish('topic', data);
});

在我申请的另一部分,我看到了这条消息:

function MyObj() {
    this.eventLog = [];
    var token = PubSub.subscribe('topic', this.logger);
};

MyObj.prototype.logger = function(message, data) {
    this.eventLog.push(data);
}

这里我想把发布的数据存储在MyObj对象的eventLog属性中。不幸的是,这不起作用:

Uncaught TypeError: Cannot read property 'eventLog' of undefined

所以 this 的上下文似乎丢失了——当我做 console.log(this) 时,window 对象被记录了。

我知道 this 对于初学者来说可能很棘手,但直到现在我总是能够理解发生了什么,但这让我完全困惑。当然 MyObj 在消息发布之前就已经初始化了,所以我看不出有什么问题。有人可以向我解释一下这里发生了什么吗?

使用Function.prototype.bind:

 PubSub.subscribe('topic', this.logger.bind(this))

为了clarify/explain观察到的行为——JavaScript使用了词法范围,所以this关键字被绑定到用法的最内层范围。根据使用 this 关键字的位置(在哪个函数和函数 and/or 对象的父对象中),它是 一个不同的对象。

在您的情况下,当您在 MyObj 中调用 this.eventLog 时,这是指 MyObj。但在

部分
MyObj.prototype.logger = function(message, data) {
    this.eventLog.push(data);
}

this 关键字在 window 对象(父对象是 window 的范围 中被调用 object),这就是为什么你在打印时看到它而不是 MyObj

从技术上讲,this 的上下文始终在堆栈中 pushed/saved,因此上下文不会 lost,但是当前上下文是关于当前范围的堆栈中的 popped/retrieved。

这篇文章 Quirksmode - The this keyword 很好地(也从视觉上)描述了这种行为。 在 this SO post.

中也可以找到一些很好的例子