你应该如何继承节点中的EventEmitter?

时间:2022-09-25 07:37:52

I was reading over this small article to understand inheriting from EventEmitter, but I'm a little confused.

我正在阅读这篇小文章,以了解继承自EventEmitter,但我有点困惑。

He does this:

他这样做:

function Door() {
    events.EventEmitter.call(this);
    this.open = function() {
        this.emit('open');
    };
}
Door.prototype.__proto__ = events.EventEmitter.prototype;

https://gist.github.com/chevex/7646362

https://gist.github.com/chevex/7646362

Why does he manually invoke the EventEmitter constructor with his own constructor's this? Also, why does he set the prototype of his contsructor's prototype to the prototype of EventEmitter? That's super confusing to me.

为什么他用自己的构造函数手动调用EventEmitter构造函数呢?另外,为什么他将他的contsructor原型的原型设置为EventEmitter的原型?这让我感到非常困惑。

Then someone in the comments suggested he do this instead, which seemed more elegant:

然后评论中有人建议他这样做,这似乎更优雅:

function Door() {
    events.EventEmitter.call(this);
    this.open = function () {
      this.emit('open');
    }
}
util.inherits(Door, events.EventEmitter);

https://gist.github.com/chevex/7646447

https://gist.github.com/chevex/7646447

This seems WAY cleaner than the other way, though that's probably just because I fail to understand what's going on in the first instance. I would not be surprised if util.inherits is doing the same thing as the first example.

这看起来比其他方式干净,但这可能只是因为我无法理解第一次发生的事情。如果util.inherits做的与第一个例子相同,我不会感到惊讶。

The second one at least makes a little sense to me, but I still don't understand why they don't just do this:

第二个至少对我有点意义,但我仍然不明白他们为什么不这样做:

function Door() {
    this.open = function () {
      this.emit('open');
    }
}
Door.prototype = new events.EventEmitter();

https://gist.github.com/chevex/7646524

https://gist.github.com/chevex/7646524

Can anyone explain to me what the differences between all of these approaches is and why in the first two they invoke .call(this) on the EventEmitter constructor? I omitted that line while trying out the examples and they still worked.

任何人都可以向我解释所有这些方法之间的区别是什么以及为什么在前两个中它们在EventEmitter构造函数上调用.call(this)?我在尝试示例时省略了这一行,但仍然有效。

4 个解决方案

#1


9  

The third example is not generally correct: that creates one single EventEmitter instance for all door instances.

第三个示例通常不正确:为所有门实例创建一个EventEmitter实例。

Let's imagine a simple case:

让我们想象一个简单的案例:

var Foo = function() {
    // each Foo instance has a unique id
    this.id = Math.random();
}
Foo.prototype.doFoo = function() { console.log("Foo!"); }

Suppose we want to create a Bar constructor that inherits from Foo and adds some new properties. If you follow your final example:

假设我们想要创建一个继承自Foo的Bar构造函数并添加一些新属性。如果你按照你的最后一个例子:

var Bar = function() {
    this.something = 5;
}
Bar.prototype = new Foo();

This is wrong because all Bar instance will have the same id property. Instead, we must call the parent constructor for each instance:

这是错误的,因为所有Bar实例都具有相同的id属性。相反,我们必须为每个实例调用父构造函数:

var Bar = function() {
    Foo.call(this);  // set unique `id` on `this`
    this.something = 5;
}
Bar.prototype = Object.create(Foo.prototype);

Note that the final line here is the same as Bar.prototype.__proto__ = Foo.prototype; because Object.create creates a new object whose __proto__ is set to the Object.create argument.

请注意,此处的最后一行与Bar.prototype相同.__ proto__ = Foo.prototype;因为Object.create创建一个新对象,其__proto__设置为Object.create参数。

#2


3  

Why does he manually invoke the EventEmitter constructor with his own constructor's this?

为什么他用自己的构造函数手动调用EventEmitter构造函数呢?

This is necessary to make sure whatever code is in the EventEmitter constructor function is executed. Some classes might not do anything interesting in the constructor, but others will have important code there, so you should always do this to make sure that code runs the same way it would run if you had just made a new EventEmitter directly with var emitter = new EventEmitter;

这是确保执行EventEmitter构造函数中的任何代码所必需的。有些类可能在构造函数中没有做任何有趣的事情,但是其他类在那里会有重要的代码,所以你应该总是这样做,以确保代码的运行方式与你刚刚使用var emitter =创建一个新的EventEmitter时的运行方式相同新的EventEmitter;

In some languages (such as Java) this "constructor chaining" type behavior is implicit, but in JavaScript it must be explicitly done.

在某些语言(例如Java)中,这种“构造函数链接”类型行为是隐式的,但在JavaScript中必须明确地完成。

Exactly how to set up inheritance in JavaScript comes down to an "it's complicated" answer and others can probably do it more justice than I. There are also several viable variations and people differ on which is preferable. However, FYI the source for util.inherits is here and the best in-depth examination of all the flavors of doing this I have seen is in this video: Douglas Crockford: Advanced JavaScript. Basically, watch that in it's entirety periodically until it sinks in.

究竟如何在JavaScript中设置继承归结为“它很复杂”的答案,而其他人可能比I更加公正。还有一些可行的变体,人们不同,哪个更好。但是,仅供参考,util.inherits的来源就在这里,我在这个视频中对所有这些风味进行了最深入的检查:Douglas Crockford:高级JavaScript。基本上,定期观察它,直到它沉入其中。

Places to look for reference. If you fully understand how all these works, you've mastered it (it still turns my brain into a pretzel at some point along the way)

寻找参考的地方。如果你完全理解所有这些是如何工作的,那么你已经掌握了它(它仍然会让我的大脑在整个过程中的某个时刻变成椒盐脆饼)

#3


3  

function Door() {
    events.EventEmitter.call(this);
}

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

In this case using events.EventEmitter.call(this) is like using super in languages which have one. It's actually can be omitted in simple cases, but it will break domain support on current node version and maybe something else in future versions.

在这种情况下,使用events.EventEmitter.call(this)就像在具有一个的语言中使用super。它实际上可以在简单的情况下省略,但它将打破当前节点版本的域支持,并可能在未来的版本中打破其他东西。

Setting __proto__ just sets up the prototype chain. At can be also done like this:

设置__proto__只是设置原型链。也可以这样做:

Door.prototype = Object.create(events.EventEmitter.prototype);

but in this case you also need to set constructor property manually.

但在这种情况下,您还需要手动设置构造函数属性。

util.inherits(Door, events.EventEmitter);

This is the idiomatic way of inheriting in node. So you are better to use this. But what it does is basically the same as above.

这是在节点中继承的惯用方法。所以你最好使用它。但它的作用与上述基本相同。

function Door() {
}
Door.prototype = new events.EventEmitter();

And this is the WRONG way, don't use it! You will end with having events shared between instances in some versions of node.

这是错误的方式,不要使用它!最终将在某些版本的节点中的实例之间共享事件。

#4


2  

The Node v6.3.1 documentation states about util.inherits(constructor, superConstructor):

Node v6.3.1文档说明了util.inherits(constructor,superConstructor):

Usage of util.inherits() is discouraged. Please use the ES6 class and extends keywords to get language level inheritance support. Also note that the two styles are semantically incompatible.

不鼓励使用util.inherits()。请使用ES6类并扩展关键字以获得语言级继承支持。另请注意,这两种样式在语义上是不兼容的。


The following code shows how to inherit from EventEmitter with Typescript:

以下代码显示了如何使用Typescript从EventEmitter继承:

import { EventEmitter } from "events"

class Person extends EventEmitter {
    constructor(public name: string) {
        super()
    }
}

let person = new Person("Bob")
person.on("speak", function (said: string) {
    console.log(`${this.name} said: ${said}`)
})
person.emit("speak", "'hello'") // prints "Bob said: 'hello'"

The previous code will transpile into the following ES6 code:

以前的代码将转换为以下ES6代码:

"use strict";
const events = require("events");
class Person extends events.EventEmitter {
    constructor(name) {
        super();
        this.name = name;
    }
}
let person = new Person("Bob");
person.on("speak", function (said) { console.log(`${this.name} said: ${said}`); });
person.emit("speak", "'hello'");

#1


9  

The third example is not generally correct: that creates one single EventEmitter instance for all door instances.

第三个示例通常不正确:为所有门实例创建一个EventEmitter实例。

Let's imagine a simple case:

让我们想象一个简单的案例:

var Foo = function() {
    // each Foo instance has a unique id
    this.id = Math.random();
}
Foo.prototype.doFoo = function() { console.log("Foo!"); }

Suppose we want to create a Bar constructor that inherits from Foo and adds some new properties. If you follow your final example:

假设我们想要创建一个继承自Foo的Bar构造函数并添加一些新属性。如果你按照你的最后一个例子:

var Bar = function() {
    this.something = 5;
}
Bar.prototype = new Foo();

This is wrong because all Bar instance will have the same id property. Instead, we must call the parent constructor for each instance:

这是错误的,因为所有Bar实例都具有相同的id属性。相反,我们必须为每个实例调用父构造函数:

var Bar = function() {
    Foo.call(this);  // set unique `id` on `this`
    this.something = 5;
}
Bar.prototype = Object.create(Foo.prototype);

Note that the final line here is the same as Bar.prototype.__proto__ = Foo.prototype; because Object.create creates a new object whose __proto__ is set to the Object.create argument.

请注意,此处的最后一行与Bar.prototype相同.__ proto__ = Foo.prototype;因为Object.create创建一个新对象,其__proto__设置为Object.create参数。

#2


3  

Why does he manually invoke the EventEmitter constructor with his own constructor's this?

为什么他用自己的构造函数手动调用EventEmitter构造函数呢?

This is necessary to make sure whatever code is in the EventEmitter constructor function is executed. Some classes might not do anything interesting in the constructor, but others will have important code there, so you should always do this to make sure that code runs the same way it would run if you had just made a new EventEmitter directly with var emitter = new EventEmitter;

这是确保执行EventEmitter构造函数中的任何代码所必需的。有些类可能在构造函数中没有做任何有趣的事情,但是其他类在那里会有重要的代码,所以你应该总是这样做,以确保代码的运行方式与你刚刚使用var emitter =创建一个新的EventEmitter时的运行方式相同新的EventEmitter;

In some languages (such as Java) this "constructor chaining" type behavior is implicit, but in JavaScript it must be explicitly done.

在某些语言(例如Java)中,这种“构造函数链接”类型行为是隐式的,但在JavaScript中必须明确地完成。

Exactly how to set up inheritance in JavaScript comes down to an "it's complicated" answer and others can probably do it more justice than I. There are also several viable variations and people differ on which is preferable. However, FYI the source for util.inherits is here and the best in-depth examination of all the flavors of doing this I have seen is in this video: Douglas Crockford: Advanced JavaScript. Basically, watch that in it's entirety periodically until it sinks in.

究竟如何在JavaScript中设置继承归结为“它很复杂”的答案,而其他人可能比I更加公正。还有一些可行的变体,人们不同,哪个更好。但是,仅供参考,util.inherits的来源就在这里,我在这个视频中对所有这些风味进行了最深入的检查:Douglas Crockford:高级JavaScript。基本上,定期观察它,直到它沉入其中。

Places to look for reference. If you fully understand how all these works, you've mastered it (it still turns my brain into a pretzel at some point along the way)

寻找参考的地方。如果你完全理解所有这些是如何工作的,那么你已经掌握了它(它仍然会让我的大脑在整个过程中的某个时刻变成椒盐脆饼)

#3


3  

function Door() {
    events.EventEmitter.call(this);
}

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

In this case using events.EventEmitter.call(this) is like using super in languages which have one. It's actually can be omitted in simple cases, but it will break domain support on current node version and maybe something else in future versions.

在这种情况下,使用events.EventEmitter.call(this)就像在具有一个的语言中使用super。它实际上可以在简单的情况下省略,但它将打破当前节点版本的域支持,并可能在未来的版本中打破其他东西。

Setting __proto__ just sets up the prototype chain. At can be also done like this:

设置__proto__只是设置原型链。也可以这样做:

Door.prototype = Object.create(events.EventEmitter.prototype);

but in this case you also need to set constructor property manually.

但在这种情况下,您还需要手动设置构造函数属性。

util.inherits(Door, events.EventEmitter);

This is the idiomatic way of inheriting in node. So you are better to use this. But what it does is basically the same as above.

这是在节点中继承的惯用方法。所以你最好使用它。但它的作用与上述基本相同。

function Door() {
}
Door.prototype = new events.EventEmitter();

And this is the WRONG way, don't use it! You will end with having events shared between instances in some versions of node.

这是错误的方式,不要使用它!最终将在某些版本的节点中的实例之间共享事件。

#4


2  

The Node v6.3.1 documentation states about util.inherits(constructor, superConstructor):

Node v6.3.1文档说明了util.inherits(constructor,superConstructor):

Usage of util.inherits() is discouraged. Please use the ES6 class and extends keywords to get language level inheritance support. Also note that the two styles are semantically incompatible.

不鼓励使用util.inherits()。请使用ES6类并扩展关键字以获得语言级继承支持。另请注意,这两种样式在语义上是不兼容的。


The following code shows how to inherit from EventEmitter with Typescript:

以下代码显示了如何使用Typescript从EventEmitter继承:

import { EventEmitter } from "events"

class Person extends EventEmitter {
    constructor(public name: string) {
        super()
    }
}

let person = new Person("Bob")
person.on("speak", function (said: string) {
    console.log(`${this.name} said: ${said}`)
})
person.emit("speak", "'hello'") // prints "Bob said: 'hello'"

The previous code will transpile into the following ES6 code:

以前的代码将转换为以下ES6代码:

"use strict";
const events = require("events");
class Person extends events.EventEmitter {
    constructor(name) {
        super();
        this.name = name;
    }
}
let person = new Person("Bob");
person.on("speak", function (said) { console.log(`${this.name} said: ${said}`); });
person.emit("speak", "'hello'");