web-dev-qa-db-ja.com

Node.js-EventEmitterから継承

かなりの数のNode.jsライブラリでこのパターンが見られます。

Master.prototype.__proto__ = EventEmitter.prototype;

(ソース ここ

誰かが例を挙げて私に説明してもらえますか、なぜこれがこのような一般的なパターンであり、いつ便利なのですか?

83
jeffreyveon

そのコードの上のコメントにあるように、MasterEventEmitter.prototypeから継承するため、その「クラス」のインスタンスを使用してイベントを発行およびリッスンできます。

たとえば、次のことができます。

masterInstance = new Master();

masterInstance.on('an_event', function () {
  console.log('an event has happened');
});

// trigger the event
masterInstance.emit('an_event');

更新:多くのユーザーが指摘したように、Nodeでそれを行う '標準'の方法は 'util.inherits'を使用することです:

var EventEmitter = require('events').EventEmitter;
util.inherits(Master, EventEmitter);
79
alessioalex

ES 6スタイルクラスの継承

これらはドキュメントから直接来ていますが、探している人のためにこの人気のある質問に追加するのはいいことだと思いました。

_const EventEmitter = require('events');

class MyEmitter extends EventEmitter {
  constructor() {
    super(); //must call super for "this" to be defined.
  }
}

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});
myEmitter.emit('event');
_

それを追加した人は誰でも_git thank_したいです。 イベントエミッター

注:ドキュメントでは、コンストラクターでsuper()を呼び出さないため、thisが未定義になります。こちらをご覧ください issue

75
Breedly

別のJavascriptオブジェクト、特にNode.jsのEventEmitterから継承するが、実際には一般的なオブジェクトから継承するには、2つのことを行う必要があります。

  • オブジェクトを完全に初期化するコンストラクターをオブジェクトに提供します。他のオブジェクトから継承している場合は、おそらくこの初期化作業の一部をスーパーコンストラクターに委任する必要があります。
  • コンストラクターから作成されたオブジェクトの[[proto]]として使用されるプロトタイプオブジェクトを提供します。他のオブジェクトから継承している場合、おそらく他のオブジェクトのインスタンスをプロトタイプとして使用する必要があります。

これは、他の言語で見られるよりもJavascriptでは複雑です

  • Javascriptは、オブジェクトの動作を「コンストラクター」と「プロトタイプ」に分けます。これらの概念は一緒に使用することを意図していますが、別々に使用することもできます。
  • Javascriptは非常に順応性のある言語であり、人々はそれを異なる方法で使用し、「継承」が意味するものの単一の真の定義はありません。
  • 多くの場合、あなたは正しいことのサブセットを行うことで逃げることができ、うまくいくように見えるたくさんの例(このSO質問に対する他の回答を含む)を見つけるでしょうあなたの場合。

Node.jsのEventEmitterの特定のケースでは、次のように機能します。

var EventEmitter = require('events').EventEmitter;
var util = require('util');

// Define the constructor for your derived "class"
function Master(arg1, arg2) {
   // call the super constructor to initialize `this`
   EventEmitter.call(this);
   // your own initialization of `this` follows here
};

// Declare that your class should use EventEmitter as its prototype.
// This is roughly equivalent to: Master.prototype = Object.create(EventEmitter.prototype)
util.inherits(Master, EventEmitter);

考えられるもの:

  • util.inheritsを使用して、または使用せずに、サブクラスのプロトタイプ(Master.prototype)を設定しますが、クラスのインスタンスに対してスーパーコンストラクター(EventEmitter)を呼び出さないと、 t適切に初期化されます。
  • スーパーコンストラクターを呼び出してもプロトタイプを設定しないと、EventEmitterメソッドはオブジェクトで機能しません
  • サブクラスコンストラクターMasterがスーパーコンストラクターEventEmitterを呼び出す代わりに、new EventEmitterとしてスーパークラスの初期化されたインスタンス(Master.prototype)を使用しようとする場合があります。スーパークラスコンストラクターの動作によっては、しばらくは正常に動作しているように見えるかもしれませんが、同じことではありません(そして、EventEmitterでは動作しません)。
  • Object.createを介してオブジェクトの追加レイヤーを追加する代わりに、スーパープロトタイプ(Master.prototype = EventEmitter.prototype)を直接使用しようとするかもしれません。これは、誰かがあなたのオブジェクトMasterにモンキーパッチを適用し、誤ってモンキーパッチを適用EventEmitterおよび他のすべての子孫にパッチを適用するまで、正常に動作しているように見えるかもしれません。各「クラス」には独自のプロトタイプが必要です。

繰り返しになりますが、EventEmitter(または実際に既存のオブジェクト「クラス」)を継承するには、スーパーコンストラクターにチェーンし、スーパープロトタイプから派生したプロトタイプを提供するコンストラクターを定義します。

38
metamatt

これは、JavaScriptでプロトタイプ(プロトタイプ?)継承が行われる方法です。 [〜#〜] mdn [〜#〜] から:

オブジェクトまたはnullの可能性があるオブジェクトのプロトタイプを参照します(通常、オブジェクトはObject.prototypeであり、プロトタイプがないことを意味します)。プロトタイプ継承ベースのプロパティルックアップの実装に使用されることがあります。

これも機能します:

var Emitter = function(obj) {
    this.obj = obj;
}

// DON'T Emitter.prototype = new require('events').EventEmitter();
Emitter.prototype = Object.create(require('events').EventEmitter.prototype);

JavaScript OOPを理解する は、最近読んだECMAScript 5のOOPで最高の記事の1つです。

19
Daff

http://www.bennadel.com/blog/2187-Extending-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm からこのアプローチを考えました:

function EventedObject(){

  // Super constructor
  EventEmitter.call( this );

  return( this );

}

ダグラス・クロックフォードには興味深い継承パターンもいくつかあります。 http://www.crockford.com/javascript/inheritance.html

JavaScriptとNode.jsでは、継承はあまり必要ありません。しかし、継承がスケーラビリティに影響を与える可能性のあるアプリを作成する際には、パフォーマンスを保守性と比較検討します。そうでなければ、どのパターンが全体的な設計の改善につながり、保守性が高く、エラーが発生しにくいかを判断するだけです。

Google Chrome(V8)を使用してjsPerfでさまざまなパターンをテストして、大まかな比較を行います。V8はNode.jsとChromeの両方で使用されるJavaScriptエンジンです。

始めるためのjsPerfsを次に示します。

http://jsperf.com/prototypes-vs-functions/4

http://jsperf.com/inheritance-proto-vs-object-create

http://jsperf.com/inheritance-perf

5
wprl

Wprlの応答に追加します。彼は「プロトタイプ」の部分を見逃した。

function EventedObject(){

   // Super constructor
   EventEmitter.call(this);

   return this;

}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part
1
guatedude2