2011-07-31 19 views
5

Tôi đã chơi thử với EventEmitter, nhưng tôi đã nhầm lẫn về cách chính xác tôi nên thực hiện nó từ một mô-đun. Tôi đã nhìn thấy một vài cách khác nhau, và tất cả chúng dường như hoạt động. Dưới đây là một vài Tôi đã nhìn thấy:Node.js - Phương pháp tốt nhất để phát ra sự kiện từ các mô-đun

Từ here:

var Twitter = function() {...}; 

Twitter.prototype = new events.EventEmitter; 

Nhưng sau đó trong "Mastering Node" họ làm điều đó theo cách này:

function Dog(name) { 
    this.name = name; 
    EventEmitter.call(this); 
} 

Dog.prototype.__proto__ = EventEmitter.prototype; 

(lý do tại sao bạn sẽ cần phải .call nó?)

Và sau đó trong mã của riêng tôi, tôi đã thử cách khác:

function Class() {} 

Class.prototype = EventEmitter.prototype; 

Tất cả chúng đều được kế thừa từ EventEmitter theo cách riêng của chúng, vậy giải pháp đơn giản nhất có phải là giải pháp tốt nhất không?

Trả lời

18

Bạn nên sử dụng kiểu thừa kế __proto__. This assumes you're coding solely for Node, or only supporting your favorite browsers. Ngoài ra, Base.call(this) là cần thiết nếu bạn quan tâm đến bất kỳ logic nào trong hàm tạo của nguyên mẫu cơ sở của bạn.

Kỹ thuật __proto__ để tham chiếu mẫu thử cơ sở sẽ đảm bảo rằng toán tử instanceof xác định chính xác các phiên bản của mẫu thử nghiệm. Thuộc tính .constructor của các phiên bản của trẻ lớp sẽ tham chiếu đến hàm tạo mà bạn mong đợi. Nó cũng có lợi ích của việc không instantiating một trường hợp mới của nguyên mẫu cơ bản.

Kiểu new Base() cũng sẽ đảm bảo rằng instanceof cung cấp cho bạn câu trả lời đúng, nhưng nó sẽ chạy hàm khởi tạo cho Cơ sở. Nói chung không phải là một vấn đề, nhưng có thể có vấn đề nếu constructor cơ sở của bạn đã yêu cầu đối số. Nó cũng sẽ đặt thuộc tính .constructor cho hàm tạo cơ sở, not the descendant constructor.

Thiết nguyên mẫu của lớp học của bạn để nguyên mẫu của các cơ sở lớp sẽ nhầm lẫn instanceof như bất kỳ con cháu của các cơ sở cũng sẽ xuất hiện để được trường hợp của đứa trẻ.

Rõ ràng là bùn, phải không? Ví dụ này sẽ giúp:

// Base constructor. 
// A, B, and C will inherit from Base. 
function Base() { 
    this.name = 'base'; 
} 

// new Base() style 
function A() { 
    Base.call(this); 
} 
A.prototype = new Base(); 

// __proto__ = prototype style 
function B() { 
    Base.call(this); 
} 
B.prototype.__proto__ = Base.prototype; 

// prototype = protoype style 
function C() { 
    Base.call(this); 
} 
C.prototype = Base.prototype; 

// create instances 
var a = new A(); 
var b = new B(); 
var c = new C(); 

// are we who we think we are? 
console.assert(a instanceof A); 
console.assert(b instanceof B); 
console.assert(c instanceof C); 
// so far so good 

// do we respect our elders? 
console.assert(a instanceof Base); 
console.assert(b instanceof Base); 
console.assert(c instanceof Base); 
// we have respect 

// test to see that Base.call(this) 
// functioned as expected 
console.assert(a.name == 'base'); 
console.assert(b.name == 'base'); 
console.assert(c.name == 'base'); 
// ok, good... 

// but now things get weird 
console.assert(a instanceof C); 
console.assert(b instanceof C); 
// that's not right! a is not C, b is not C! 

// At least A and B do not confuse identities 
console.assert(!(a instanceof B)); 
console.assert(!(b instanceof A)); 

console.assert(!(c instanceof A)); 
console.assert(!(c instanceof B)); 

// so we've determined that style C is no good. 
// C confuses the inheritance chain. 

// B is the winner. 

// Why? Only B passes this test 
console.assert(b.constructor == B); 

// a and c's constructors actually point to the Base constructor 
console.assert(a.constructor == Base); 
console.assert(c.constructor == Base); 

// Word B. 
+1

Xin cảm ơn bạn. Tôi ước tôi có thể đưa ra nhiều hơn một upvote cho câu trả lời này. –

20

Nút có chức năng thư viện, util.inherits, hơi đơn giản hơn câu trả lời được chấp nhận. Mã dưới đây được sửa đổi từ v0.8.12 docs.

var util = require("util"); 
var events = require("events"); 

function MyStream() { 
    events.EventEmitter.call(this); 
} 

util.inherits(MyStream, events.EventEmitter); 
+0

Tôi có [câu hỏi này] (http://stackoverflow.com/questions/24809786/different-ways-of-extending-classes-in-node-js) có phần liên quan đến điều này. Bạn có phiền không? – majidarif

+0

Ngoài ra bạn có thể giải thích 'events.EventEmitter.call (this);' và tại sao điều này là cần thiết hoặc nếu nó có thể bỏ qua nó? – majidarif

+1

@majidarif Câu trả lời ngắn gọn là cuộc gọi thực hiện chức năng EventEmitter với cá thể MyStream dưới dạng biến "this", vì vậy nó sẽ đi qua tất cả các khởi tạo EventEmitter cho các cá thể MyStream. Hy vọng rằng có ý nghĩa. – bmavity

Các vấn đề liên quan