꽤 많은 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에 복사하여 붙여넣고 생성자를 완전히 제거하면 동일한 방식으로 작동합니다. 그것은 완벽하게 유효한 구문입니다.
다른 자바 스크립트 객체, 특히 Node.js의 EventEmitter (특히 일반적으로 모든 객체)에서 상속하려면 두 가지 작업을 수행해야합니다.
[[proto]]
생성자에서 생성 된 객체의 으로 사용될 프로토 타입 객체를 제공합니다 . 다른 개체에서 상속하는 경우 다른 개체의 인스턴스를 프로토 타입으로 사용하고 싶을 것입니다.이것은 다른 언어에서 보이는 것보다 자바 스크립트에서 더 복잡합니다.
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
하지만 EventEmitter
클래스 인스턴스에 대해 슈퍼 생성자 ( )를 호출하지 않으면 제대로 초기화되지 않습니다.new EventEmitter
) 의 초기화 된 인스턴스를 사용하려고 할 수 있습니다 . 잠시 동안 잘 작동하는 것처럼 보일 수 있지만 동일한 것은 아닙니다 (EventEmitter에서는 작동하지 않음).Master.prototype
Master
EventEmitter
Master.prototype = EventEmitter.prototype
Object.create를 통해 객체의 추가 레이어를 추가하는 대신 수퍼 프로토 타입 ( )을 직접 사용하려고 할 수 있습니다 . 누군가가 당신의 객체 Master
를 몽키 패치 EventEmitter
하고 우연히 몽키 패치 와 다른 모든 자손을 가질 때까지 잘 작동하는 것처럼 보일 수 있습니다 . 각 "클래스"에는 자체 프로토 타입이 있어야합니다.다시 말하지만, EventEmitter (또는 실제로 기존 객체 "클래스")에서 상속하려면 수퍼 생성자에 연결하고 수퍼 프로토 타입에서 파생 된 프로토 타입을 제공하는 생성자를 정의해야합니다.
이것이 자바 스크립트에서 프로토 타입 (prototypal?) 상속이 수행되는 방식입니다. 에서 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에 대해 읽은 최고의 기사 중 하나입니다.
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 );
}
Douglas Crockford에도 몇 가지 흥미로운 상속 패턴이 있습니다. 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