このパターンは、かなりの数のNode.jsライブラリで見られます。
Master.prototype.__proto__ = EventEmitter.prototype;
(ソースはこちら)
誰かが例を挙げて私に説明してもらえますか、なぜこれがそのような一般的なパターンであり、それが便利なのですか?
このパターンは、かなりの数のNode.jsライブラリで見られます。
Master.prototype.__proto__ = EventEmitter.prototype;
(ソースはこちら)
誰かが例を挙げて私に説明してもらえますか、なぜこれがそのような一般的なパターンであり、それが便利なのですか?
__proto__
はアンチパターンです。使用してくださいMaster.prototype = Object.create(EventEmitter.prototype);
util.inherits(Master, EventEmitter);
回答:
そのコードの上のコメントが言うように、それはMaster
から継承するEventEmitter.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);
2回目の更新:ES6クラスを使用しているため、EventEmitter
今すぐクラスを拡張することをお勧めします。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
require('events').EventEmitter
最初に行うべきちょっとしたリマインダー-私はいつも忘れています。他の誰かがそれを必要とする場合に備えて、ドキュメントへのリンクは次のとおりです:nodejs.org/api/events.html#events_class_events_eventemitter)
MasterInstance
必要がありますmasterInstance
。
Master.prototype = EventEmitter.prototype;
です。スーパーの必要はありません。このようにES6拡張機能を使用することもできます(Node.jsのドキュメントで推奨されていますutil.inherits
)。class Master extends EventEmitter
クラシックsuper()
になりますが、に何も挿入しませんMaster
。
Nodeのドキュメントでは、クラス継承を使用して独自のイベントエミッターを作成することを推奨しています。
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {
// Add any custom methods here
}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
注:でconstructor()
関数を定義する場合はMyEmitter
、そうしsuper()
ない正当な理由がない限り、関数を呼び出して、親クラスのコンストラクターも呼び出されるようにする必要があります。
super()
されて必要はありません、限り、あなたは、コンストラクタを定義/必要としないようとして、それ故にBreedlyのオリジナルの答えを(編集履歴を参照してください)完全に正しかったです。この場合、これとまったく同じ例をコピーしてreplに貼り付け、コンストラクターを完全に削除すると、同じように機能します。これは完全に有効な構文です。
別のJavascriptオブジェクト、特にNode.jsのEventEmitterから継承するには、実際には一般的なオブジェクトであるため、次の2つのことを行う必要があります。
[[proto]]
コンストラクターから作成されたオブジェクトのforとして使用されるプロトタイプオブジェクトを提供します。他のオブジェクトから継承している場合は、他のオブジェクトのインスタンスをプロトタイプとして使用することをお勧めします。これは、Javascriptでは他の言語よりも複雑です。
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
が、クラスのインスタンスに対してスーパーコンストラクター()を呼び出さない場合、それらは適切に初期化されません。new EventEmitter
)の初期化されたインスタンスを使用しようとする場合があります。スーパークラスコンストラクターの動作によっては、しばらくは正常に機能しているように見えるかもしれませんが、同じではありません(EventEmitterでは機能しません)。Master.prototype
Master
EventEmitter
Master.prototype = EventEmitter.prototype
Object.createを介してオブジェクトのレイヤーを追加する代わりに、スーパープロトタイプを直接使用しようとする場合があります()。これは、誰かがオブジェクトにモンキーパッチを適用し、Master
うっかりしてモンキーパッチEventEmitter
と他のすべての子孫もパッチを適用するまでは、正常に機能しているように見える場合があります。各「クラス」には、独自のプロトタイプが必要です。繰り返しますが、EventEmitter(または実際には既存のオブジェクト「クラス」)から継承するには、スーパーコンストラクターにチェーンし、スーパープロトタイプから派生したプロトタイプを提供するコンストラクターを定義する必要があります。
これは、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を理解することは、ECMAScript5のOOPについて最近読んだ最高の記事の1つです。
Y.prototype = new X();
はアンチパターンです。使用してくださいY.prototype = Object.create(X.prototype);
new X()
のインスタンスをインスタンス化し、X.prototype
それを呼び出すことによって初期化しますX
。Object.create(X.prototype)
インスタンスをインスタンス化するだけです。Emitter.prototype
初期化する必要はありません。これを説明する良い記事が見つかりません。
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
emit
を試しましon
たが、未定義として出てきています。
wprlの応答に追加します。彼は「プロトタイプ」の部分を見逃しました:
function EventedObject(){
// Super constructor
EventEmitter.call(this);
return this;
}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part