Tôi thấy mẫu này trong khá nhiều thư viện Node.js:
Master.prototype.__proto__ = EventEmitter.prototype;
(nguồn tại đây )
Ai đó có thể vui lòng giải thích cho tôi với một ví dụ, tại sao đây là một mô hình phổ biến như vậy và khi nào nó tiện dụng?
Tôi thấy mẫu này trong khá nhiều thư viện Node.js:
Master.prototype.__proto__ = EventEmitter.prototype;
(nguồn tại đây )
Ai đó có thể vui lòng giải thích cho tôi với một ví dụ, tại sao đây là một mô hình phổ biến như vậy và khi nào nó tiện dụng?
__proto__là một mô hình chống, hãy sử dụngMaster.prototype = Object.create(EventEmitter.prototype);
util.inherits(Master, EventEmitter);
Câu trả lời:
Như nhận xét ở trên, đoạn mã đó sẽ tạo Masterkế thừa từ đó EventEmitter.prototype, vì vậy bạn có thể sử dụng các phiên bản của 'lớp' đó để phát ra và lắng nghe các sự kiện.
Ví dụ, bây giờ bạn có thể làm:
masterInstance = new Master();
masterInstance.on('an_event', function () {
console.log('an event has happened');
});
// trigger the event
masterInstance.emit('an_event');
Cập nhật : như nhiều người dùng đã chỉ ra, cách 'tiêu chuẩn' để làm điều đó trong Node sẽ là sử dụng 'use.inherits':
var EventEmitter = require('events').EventEmitter;
util.inherits(Master, EventEmitter);
Cập nhật lần 2 : với các lớp ES6 cho chúng tôi, bạn nên mở rộng EventEmitterlớp học ngay bây giờ:
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').EventEmitterfirst-- Tôi luôn luôn quên Dưới đây là các liên kết đến các tài liệu trong nhu cầu khác trường hợp ai đó:. nodejs.org/api/events.html#events_class_events_eventemitter )
MasterInstancenên masterInstance.
Master.prototype = EventEmitter.prototype;. Không cần supers. Bạn cũng có thể sử dụng ES6 mở rộng (và nó được khuyến khích trong tài liệu Node.js trên util.inherits) như thế này class Master extends EventEmitter- bạn nhận được cổ điển super(), nhưng không cần tiêm bất cứ thứ gì vào Master.
Các tài liệu Node hiện khuyên bạn nên sử dụng tính năng kế thừa lớp để tạo bộ phát sự kiện của riêng bạn:
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');
Lưu ý: Nếu bạn định nghĩa một constructor()hàm trong MyEmitter, bạn nên gọi super()từ nó để đảm bảo hàm tạo của lớp cha cũng được gọi, trừ khi bạn có lý do chính đáng để không làm như vậy.
super()là không bắt buộc , miễn là bạn không cần / xác định một phương thức khởi tạo, do đó câu trả lời ban đầu của Breedly (xem lịch sử EDIT) là hoàn toàn chính xác. Trong trường hợp này, bạn có thể sao chép và dán chính ví dụ này vào repl, xóa hoàn toàn hàm tạo và nó sẽ hoạt động theo cách tương tự. Đó là cú pháp hoàn toàn hợp lệ.
Để kế thừa từ một đối tượng Javascript khác, EventEmitter của Node.js nói riêng nhưng thực sự là bất kỳ đối tượng nào nói chung, bạn cần thực hiện hai việc:
[[proto]]đối tượng được tạo từ phương thức khởi tạo của bạn; trong trường hợp bạn đang kế thừa từ một số đối tượng khác, bạn có thể muốn sử dụng một thể hiện của đối tượng kia làm nguyên mẫu của mình.Điều này phức tạp hơn trong Javascript so với các ngôn ngữ khác vì
Đối với trường hợp cụ thể của EventEmitter của Node.js, đây là những gì hoạt động:
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);
Fibles có thể có:
util.inherits, nhưng không gọi hàm tạo siêu ( EventEmitter) cho các thể hiện của lớp của bạn, chúng sẽ không được khởi tạo đúng cách.new EventEmitter) Master.prototypethay vì để hàm tạo của lớp con Mastergọi hàm tạo siêu EventEmitter; tùy thuộc vào hành vi của hàm tạo lớp cha có thể có vẻ như nó hoạt động tốt trong một thời gian, nhưng không giống như vậy (và sẽ không hoạt động đối với EventEmitter).Master.prototype = EventEmitter.prototype) thay vì thêm một lớp đối tượng bổ sung thông qua Object.create; điều này có vẻ như nó hoạt động tốt cho đến khi ai đó khớp với đối tượng của bạn Mastervà vô tình cũng đã khớp khỉ EventEmittervà tất cả các con cháu khác của nó. Mỗi "lớp" nên có nguyên mẫu riêng của nó.Một lần nữa: để kế thừa từ EventEmitter (hoặc thực sự là bất kỳ "lớp" đối tượng hiện có nào), bạn muốn xác định một phương thức khởi tạo nối chuỗi với phương thức siêu khởi tạo và cung cấp một nguyên mẫu có nguồn gốc từ siêu nguyên mẫu.
Đây là cách kế thừa nguyên mẫu (nguyên mẫu?) Được thực hiện trong JavaScript. Từ MDN :
Đề cập đến nguyên mẫu của đối tượng, có thể là một đối tượng hoặc null (thường có nghĩa là đối tượng là Object.prototype, không có nguyên mẫu). Nó đôi khi được sử dụng để thực hiện tra cứu tài sản dựa trên nguyên mẫu-kế thừa.
Điều này cũng hoạt động:
var Emitter = function(obj) {
this.obj = obj;
}
// DON'T Emitter.prototype = new require('events').EventEmitter();
Emitter.prototype = Object.create(require('events').EventEmitter.prototype);
Hiểu về JavaScript OOP là một trong những bài viết hay nhất mà tôi đọc gần đây về OOP trong ECMAScript 5.
Y.prototype = new X();là một mô hình chống, hãy sử dụngY.prototype = Object.create(X.prototype);
new X()khởi tạo một thể hiện của X.prototypevà khởi tạo nó bằng cách gọi Xtrên đó. Object.create(X.prototype)chỉ khởi tạo một thể hiện. Bạn không muốn Emitter.prototypeđược khởi tạo. Tôi không thể tìm thấy một bài báo tốt giải thích điều này.
Tôi nghĩ rằng cách tiếp cận này từ http://www.bennadel.com/blog/2187-Exfining-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm khá gọn gàng:
function EventedObject(){
// Super constructor
EventEmitter.call( this );
return( this );
}
Douglas Crockford cũng có một số mẫu kế thừa thú vị: http://www.crockford.com/javascript/inheritance.html
Tôi thấy rằng tính kế thừa ít cần thiết hơn trong JavaScript và Node.js. Nhưng khi viết một ứng dụng mà tính kế thừa có thể ảnh hưởng đến khả năng mở rộng, tôi sẽ xem xét hiệu suất được cân nhắc dựa trên khả năng bảo trì. Nếu không, tôi sẽ chỉ đưa ra quyết định dựa trên những mẫu nào dẫn đến thiết kế tổng thể tốt hơn, dễ bảo trì hơn và ít lỗi hơn.
Kiểm tra các mẫu khác nhau trong jsPerf, sử dụng Google Chrome (V8) để có một so sánh sơ bộ. V8 là công cụ JavaScript được sử dụng bởi cả Node.js và Chrome.
Dưới đây là một số jsPerfs để giúp bạn bắt đầu:
http://jsperf.com/prototypes-vs-functions/4
emitvà onsắp tới là không xác định.
Để thêm vào phản hồi của wprl. Anh ấy đã bỏ lỡ phần "nguyên mẫu":
function EventedObject(){
// Super constructor
EventEmitter.call(this);
return this;
}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part
util.inheritsvì rất nhiều người thông minh sẽ cập nhật các tùy chọn đó cho bạn.