【问题标题】:Calling the EventEmitter twice in the same class?在同一个类中调用 EventEmitter 两次?
【发布时间】:2018-09-17 22:43:17
【问题描述】:

我目前正在 NodeJS 中的 EventEmitter 上阅读 a quick tutorial。这是该教程中的示例之一:

var events = require('events');

function Door(colour) {
  this.colour = colour;
  events.EventEmitter.call(this);

  this.open = function()
  {
  this.emit('open');
  }
}

Door.prototype.__proto__ = events.EventEmitter.prototype;

var frontDoor = new Door('brown');

frontDoor.on('open', function() {
    console.log('ring ring ring');
  });
frontDoor.open();

有些东西我不明白。在第 5 行,我们call EventEmitter。如果我没记错的话,这让我们以后可以做类似的事情:

var myDoor = new Door('green');
myDoor.on('open', ...);

所以基本上它允许直接从Door 类的实例中使用属于EventEmitter 类的方法,对吧?

那么,第 13 行代码 (Door.prototype.__proto__ = events.EventEmitter.prototype;) 的用途是什么?这会将EventEmitter 的属性复制到Door 类。但是,call 方法不是已经完成了吗?

我想我错过了一些东西......我希望你能帮助我理解所有这些东西。

谢谢。

【问题讨论】:

  • 现在没有时间输入正确的答案,但基本上调用的用途是处理 EventEmitter 构造函数中的任何初始设置。分配原型允许您调用它的函数,但是当它们尝试访问由于您没有执行构造函数而从未初始化过的实例的属性时它们会失败。
  • 正在输入类似于 @Bligglenuber 的解释(不打算作为答案,因为我对 Node 的了解只是粗略,而且我从未听说过 EventEmitter )。如果您熟悉其他语言的 OOP,我要补充的一件事是,在函数 MyFunction 中调用 OtherFunction.call(this)(假设两者都是“构造函数”)本质上是基于原型的 @987654335 @ 是 OtherFunction 的“子类”,并在子类的构造函数中调用 super。
  • 为什么不使用 ES6 语法来定义一个新类并继承自 EventEmitter?它更简单。

标签: javascript node.js oop events module


【解决方案1】:

调用构造函数允许您使用父函数并将子实例替换为this。这允许进行任何初始化,但它不会将父函数的原型添加到子函数。这是一个简单的例子:

function Parent(name){
  this.name = name
  this.somProp = "some prop for " + name
}

Parent.prototype.test = function(){
  console.log(this.name, "testing")
}

// use Parent:

let p = new Parent("parent instance")
p.test()


function Child(name){
  // call parent constructor puts `.somProp` on your instance
  Parent.call(this, name)
}

let c = new Child("C")
// child instance has somProp because we called the parent constructor
console.log(c)

// BUT THIS IS AN ERROR //
// becuase it doesn't inherit the prototype //

c.test()

通过将__proto__ 属性设置为父函数原型,您现在可以访问父原型上的函数:

function Parent(name){
  this.name = name
  this.somProp = "some prop for " + name
}

Parent.prototype.test = function(){
  console.log(this.name, "testing")
}

function Child(name){
  Parent.call(this, name)
}
Child.prototype.__proto__  = Parent.prototype

let c = new Child("C")
c.test()  // now this works

不清楚的是,您是否需要在 EventEmitter 构造函数中初始化任何内容。如果您查看文档,您会看到发射器在调用函数时将this 设置为EventEmitter 实例。因此,您可以查看使用call 初始化实例和不初始化实例之间的差异。例如,如果您没有 call 超类,您的实例将没有您可能想要的 _maxListeners。

【讨论】:

  • 感谢您的回答!这是直截了当的,我终于(真正)理解了call() 函数的作用。
猜你喜欢
  • 2015-04-13
  • 2019-04-29
  • 1970-01-01
  • 2022-11-22
  • 1970-01-01
  • 1970-01-01
  • 2010-09-28
  • 2017-01-17
  • 2017-09-13
相关资源
最近更新 更多