Node.js - EventEmitter से विरासत में मिला


89

मैं इस पैटर्न को कुछ Node.js पुस्तकालयों में देखता हूं:

Master.prototype.__proto__ = EventEmitter.prototype;

( यहां स्रोत )

क्या कोई मुझे एक उदाहरण के साथ समझा सकता है, यह इतना सामान्य पैटर्न क्यों है और जब यह आसान है?


जानकारी के लिए इस सवाल का संदर्भ लें stackoverflow.com/questions/5398487/…
Juicy Scripter

14
नोट __proto__एक विरोधी पैटर्न है, कृपया उपयोग करेंMaster.prototype = Object.create(EventEmitter.prototype);
Raynos

69
वास्तव में, उपयोगutil.inherits(Master, EventEmitter);
thesmart

1
@ रेयानोस एक विरोधी पैटर्न क्या है?
०१ पर starbeamrainbowlabs

1
यह अब ES6 क्लास कंस्ट्रक्टर्स के साथ आसान हो गया है। चेक यहाँ Compat: kangax.github.io/compat-table/es6 । नीचे दिए गए डॉक्स या मेरे उत्तर की जाँच करें।
ब्रीडली

जवाबों:


84

जैसा कि उस कोड के ऊपर दी गई टिप्पणी कहती है, यह Masterविरासत से बना देगा EventEmitter.prototype, इसलिए आप उस 'वर्ग' के उदाहरणों का उपयोग कर सकते हैं और घटनाओं को सुन सकते हैं।

उदाहरण के लिए आप अब कर सकते हैं:

masterInstance = new Master();

masterInstance.on('an_event', function () {
  console.log('an event has happened');
});

// trigger the event
masterInstance.emit('an_event');

अपडेट : जैसा कि कई उपयोगकर्ताओं ने बताया, नोड में ऐसा करने का 'मानक' तरीका 'use.inherits' का उपयोग करना होगा:

var EventEmitter = require('events').EventEmitter;
util.inherits(Master, EventEmitter);

दूसरा अद्यतन : हम पर 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');

Https://nodejs.org/api/events.html#events_events देखें


4
(पहले करने के लिए बस थोड़ा सा अनुस्मारक require('events').EventEmitter- मैं हमेशा भूल जाता हूं। यहां डॉक्स का लिंक किसी और के मामले में भी है: किसी को भी इसकी आवश्यकता है: nodejs.org/api/events.html#events_class_events_eventemitter )
mcermcneil

3
बीटीडब्ल्यू, उदाहरणों के लिए सम्मेलन पहले अक्षर को कम MasterInstanceकरना है, इसलिए होना चाहिए masterInstance
खोमेस्टर

और कैसे आप की जाँच करने की क्षमता बनाए रखने के लिए अगर:
जयरोज़ो

3
util.inheritssuper_संपत्ति में Masterवस्तु को इंजेक्ट करने का एक गंदा काम करता है । यह अनावश्यक है और क्लासिक वंशानुक्रम जैसी प्रोटोटाइप विरासत का इलाज करने की कोशिश करता है। स्पष्टीकरण के लिए इस पृष्ठ के निचले भाग पर एक नज़र डालें ।
klh

2
@loretoparisi बस Master.prototype = EventEmitter.prototype;। सुपरर्स की जरूरत नहीं। आप ES6 एक्सटेंड्स का उपयोग भी कर सकते हैं (और यह util.inheritsइस तरह Node.js डॉक्स में प्रोत्साहित किया गया है ) class Master extends EventEmitter- आप शास्त्रीय प्राप्त करते हैं super(), लेकिन कुछ भी इंजेक्ट किए बिना Master
klh

81

ईएस 6 स्टाइल क्लास इनहेरिटेंस

नोड डॉक अब अपने स्वयं के ईवेंट को उत्सर्जित करने के लिए वर्ग उत्तराधिकार का उपयोग करने की सलाह देते हैं :

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()अभिभावक वर्ग के निर्माता को यह सुनिश्चित करने के लिए कॉल करना चाहिए , जब तक कि आपके पास कोई अच्छा कारण न हो।


9
ये टिप्पणियां सही नहीं हैं और अंत में इस मामले में भ्रामक हैं। कॉलिंग super()की आवश्यकता नहीं है , जब तक आपको एक निर्माता की आवश्यकता / परिभाषित नहीं होती है, इसलिए ब्रीडली का मूल उत्तर (EDIT इतिहास देखें) पूरी तरह से सही था। इस मामले में आप उत्तर में इस एक ही उदाहरण को कॉपी और पेस्ट कर सकते हैं, कंस्ट्रक्टर को पूरी तरह से हटा सकते हैं और यह उसी तरह काम करेगा। यह पूरी तरह से वैध सिंटैक्स है।
ऑरेलियो

39

किसी अन्य जावास्क्रिप्ट ऑब्जेक्ट से विरासत में प्राप्त करने के लिए, विशेष रूप से 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);

संभावित तंतु:

  • यदि आप अपने उपवर्ग (Master.prototype) के लिए या बिना उपयोग के प्रोटोटाइप का उपयोग करते हैं util.inherits, लेकिन EventEmitterअपनी कक्षा के उदाहरणों के लिए सुपर कंस्ट्रक्टर ( ) को कॉल न करें , तो वे ठीक से प्रारंभ नहीं किए जाएंगे।
  • यदि आप सुपर कंस्ट्रक्टर को कॉल करते हैं, लेकिन प्रोटोटाइप सेट नहीं करते हैं, तो EventEmitter विधियां आपके ऑब्जेक्ट पर काम नहीं करेंगी
  • आप सुपरक्लास के प्रारंभिक उदाहरण का उपयोग करने की कोशिश कर सकते हैं ( new EventEmitter) Master.prototypeइसके बजाय उप-निर्माण निर्माता Masterको सुपर कंस्ट्रक्टर कहें EventEmitter; सुपरक्लास कंस्ट्रक्टर के व्यवहार पर निर्भर करता है कि ऐसा लग सकता है कि यह थोड़ी देर के लिए ठीक काम कर रहा है, लेकिन यह एक ही चीज नहीं है (और EventEmitter के लिए काम नहीं करेगा)।
  • आप Master.prototype = EventEmitter.prototypeऑब्जेक्ट के माध्यम से ऑब्जेक्ट की अतिरिक्त परत जोड़ने के बजाय सीधे सुपर प्रोटोटाइप ( ) का उपयोग करने का प्रयास कर सकते हैं ; ऐसा लगता है कि यह तब तक ठीक काम कर सकता है जब तक कि कोई आपकी वस्तु Masterको बंद नहीं कर देता है EventEmitterऔर अनजाने में भी बंदर और उसके अन्य सभी वंशज हो जाते हैं। प्रत्येक "क्लास" का अपना प्रोटोटाइप होना चाहिए।

फिर से: EventEmitter (या वास्तव में किसी भी मौजूदा वस्तु "वर्ग" से विरासत में), आप एक कंस्ट्रक्टर को परिभाषित करना चाहते हैं जो सुपर कंस्ट्रक्टर को चेन प्रदान करता है और एक प्रोटोटाइप प्रदान करता है जो सुपर प्रोटोटाइप से प्राप्त होता है।


19

यह कैसे जावास्क्रिप्ट में प्रोटोटाइप (प्रोटोटाइप) है। से MDN :

ऑब्जेक्ट के प्रोटोटाइप का संदर्भ देता है, जो एक ऑब्जेक्ट या शून्य हो सकता है (जिसका आमतौर पर मतलब है ऑब्जेक्ट ऑब्जेक्ट.प्रोटोटाइप, जिसमें कोई प्रोटोटाइप नहीं है)। इसका उपयोग कभी-कभी प्रोटोटाइप-इनहेरिटेंस बेस्ड प्रॉपर्टी लुकअप को लागू करने के लिए किया जाता है।

यह भी काम करता है:

var Emitter = function(obj) {
    this.obj = obj;
}

// DON'T Emitter.prototype = new require('events').EventEmitter();
Emitter.prototype = Object.create(require('events').EventEmitter.prototype);

जावास्क्रिप्ट को समझना OOP सबसे अच्छे लेखों में से एक है जिसे मैंने हाल ही में ECMAScript 5 में OOP पर पढ़ा है।


7
Y.prototype = new X();एक विरोधी पैटर्न है, कृपया उपयोग करेंY.prototype = Object.create(X.prototype);
Raynos

यह जानकर अच्छा लगता है। क्या मैं कहीं और पढ़ सकता हूं? रुचि होगी कि परिणामी वस्तुएं कैसे भिन्न हैं।
डफ

4
new X()का एक उदाहरण तात्कालिकता X.prototypeऔर उस Xपर आह्वान द्वारा इसे इनिशियलाइज़ करता है । Object.create(X.prototype)बस एक उदाहरण है। आप Emitter.prototypeआरंभीकृत नहीं करना चाहते हैं। मुझे एक अच्छा लेख नहीं मिला जो यह बताता हो।
रेयोनोस

यह समझ में आता है। इस पर ध्यान दिलाने के लिए धन्यवाद। फिर भी नोड पर अच्छी आदतों को पाने की कोशिश कर रहा है। ब्राउज़र केवल ECMA5 के लिए नहीं हैं (और जैसा कि मैंने समझा कि शिम सबसे विश्वसनीय नहीं है)।
डफ

1
दूसरी कड़ी भी टूटी है। इसे आज़माएं: robotlolita.github.io/2011/10/09/…
jlukanta

5

मुझे लगा कि यह दृष्टिकोण 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

मुझे लगता है कि जावास्क्रिप्ट और Node.js. में विरासत अक्सर कम होती है लेकिन एक ऐप लिखने में जहां विरासत में स्केलेबिलिटी को प्रभावित किया जा सकता है, मैं प्रदर्शन को बनाए रखने के खिलाफ तौला जाएगा। अन्यथा, मैं केवल अपने निर्णय को आधार बनाऊंगा, जिस पर पैटर्न बेहतर समग्र डिजाइन की ओर ले जाते हैं, अधिक रखरखाव योग्य होते हैं, और कम त्रुटि-प्रवण होते हैं।

एक तुलना करने के लिए Google Chrome (V8) का उपयोग करके jsPerf में अलग-अलग पैटर्न का परीक्षण करें। V8 जावास्क्रिप्ट इंजन है जिसका उपयोग Node.js और Chrome दोनों द्वारा किया जाता है।

यहाँ कुछ jsPerfs आरंभ करने के लिए हैं:

http://jsperf.com/prototypes-vs-functions/4

http://jsperf.com/inheritance-proto-vs-object-create

http://jsperf.com/inheritance-perf


1
मैं इस दृष्टिकोण और दोनों की कोशिश की है emitऔर onके रूप में अपरिभाषित आ रहे हैं।
डोपाट्रमन

रिटर्न (यह) नहीं है; सिर्फ चेनिंग के लिए?
ब्लोबैब्ला

1

Wprl की प्रतिक्रिया को जोड़ने के लिए। उन्होंने "प्रोटोटाइप" भाग को याद किया:

function EventedObject(){

   // Super constructor
   EventEmitter.call(this);

   return this;

}
EventObject.prototype = new EventEmitter(); //<-- you're missing this part

1
वास्तव में, आपको नए के बजाय Object.create का उपयोग करना चाहिए अन्यथा आपको उदाहरण के साथ-साथ प्रोटोटाइप पर व्यवहार के साथ-साथ अन्यत्र भी बताया गया है । लेकिन ईएस 6 और ट्रांसपाइल का उपयोग करना बेहतर है या util.inheritsचूंकि बहुत सारे स्मार्ट लोग आपके लिए उन विकल्पों को रखेंगे।
कूल ब्लू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.