ฉันเห็นรูปแบบนี้ในไลบรารี 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 (ดูประวัติการแก้ไข) เป็นถูกต้องทั้งหมด ในกรณีนี้คุณสามารถคัดลอกและวางตัวอย่างเดียวกันนี้ในการจำลองได้ให้ลบตัวสร้างทั้งหมดและมันจะทำงานในลักษณะเดียวกัน นั่นคือไวยากรณ์ที่ถูกต้องอย่างสมบูรณ์
ในการสืบทอดจากวัตถุ Javascript อื่นโดยเฉพาะ EventEmitter ของ Node.js แต่โดยทั่วไปแล้วคุณต้องทำสองสิ่ง:
[[proto]]
วัตถุที่สร้างจากตัวสร้างของคุณ ในกรณีที่คุณกำลังรับช่วงจากวัตถุอื่นคุณอาจต้องการใช้ตัวอย่างของวัตถุอื่นเป็นต้นแบบของคุณสิ่งนี้มีความซับซ้อนใน Javascript มากกว่าภาษาอื่น ๆ เนื่องจาก
สำหรับกรณีเฉพาะของ EventEmitter ของ Node.js สิ่งที่ได้ผลมีดังนี้
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
ก็ได้ แต่อย่าเรียก super constructor ( EventEmitter
) สำหรับอินสแตนซ์ของคลาสของคุณจะไม่ได้รับการเตรียมใช้งานอย่างถูกต้องnew EventEmitter
) Master.prototype
แทนการให้ตัวสร้างคลาสย่อยMaster
เรียกตัวสร้างขั้นEventEmitter
สูง ขึ้นอยู่กับลักษณะการทำงานของตัวสร้างคลาสระดับสูงที่อาจดูเหมือนว่ามันทำงานได้ดีในช่วงหนึ่ง แต่ไม่ใช่สิ่งเดียวกัน (และจะไม่ทำงานกับ EventEmitter)Master.prototype = EventEmitter.prototype
) แทนการเพิ่มชั้นของวัตถุเพิ่มเติมผ่าน Object.create; สิ่งนี้อาจดูเหมือนว่ามันใช้งานได้ดีจนกว่าจะมีคนจับลิงวัตถุของคุณMaster
และมี Monkeypatched EventEmitter
และลูกหลานอื่น ๆ ทั้งหมดโดยไม่ได้ตั้งใจ "คลาส" แต่ละชั้นควรมีต้นแบบของตัวเองอีกครั้ง: ในการสืบทอดจาก EventEmitter (หรืออ็อบเจ็กต์ "คลาส" ที่มีอยู่จริงๆ) คุณต้องการกำหนดคอนสตรัคเตอร์ที่เชื่อมโยงกับตัวสร้างขั้นสูงและจัดเตรียมต้นแบบที่ได้มาจากซูเปอร์ต้นแบบ
นี่คือวิธีการสืบทอดต้นแบบ (prototypal?) ใน JavaScript จากMDN :
หมายถึงต้นแบบของวัตถุซึ่งอาจเป็นวัตถุหรือโมฆะ (ซึ่งโดยปกติหมายถึงวัตถุคือ 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เป็นหนึ่งในบทความที่ดีที่สุดที่ฉันอ่านเมื่อเร็ว ๆ นี้เกี่ยวกับ OOP ใน ECMAScript 5
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 แต่ในการเขียนแอปที่การสืบทอดอาจส่งผลต่อความสามารถในการขยายขนาดฉันจะพิจารณาประสิทธิภาพที่ชั่งเทียบกับการบำรุงรักษา มิฉะนั้นฉันจะตัดสินใจเฉพาะว่ารูปแบบใดนำไปสู่การออกแบบโดยรวมที่ดีขึ้นสามารถบำรุงรักษาได้มากกว่าและมีข้อผิดพลาดน้อยลง
ทดสอบรูปแบบต่างๆใน jsPerf โดยใช้ Google Chrome (V8) เพื่อเปรียบเทียบคร่าวๆ V8 เป็นเอ็นจิ้น JavaScript ที่ใช้โดยทั้ง Node.js และ Chrome
นี่คือ 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
util.inherits
เนื่องจากคนฉลาดจำนวนมากจะอัปเดตตัวเลือกเหล่านั้นให้คุณอยู่เสมอ