2012-06-05 15 views
13

मैं जावास्क्रिप्ट में "विरासत" के बारे में बहुत से लेख पढ़ रहा हूं। उनमें से कुछ new का उपयोग करते हैं जबकि अन्य Object.Create की सिफारिश करते हैं। जितना अधिक मैंने पढ़ा, उतना भ्रमित मुझे लगता है क्योंकि यह विरासत को हल करने के लिए भिन्न प्रकार की भिन्नता मौजूद है।सही जावास्क्रिप्ट विरासत

क्या कोई मुझे सबसे स्वीकार्य तरीका दिखाने के लिए दयालु हो सकता है (या यदि कोई है तो डिफैक्टो मानक)?

(मैं एक आधार वस्तु Model जो मैं RestModel या LocalStorageModel विस्तार कर सकते हैं करना चाहते हैं।)

उत्तर

11

सरल: Object.create सभी वातावरण में समर्थित नहीं है, लेकिन new साथ shimmed जा सकता है। इसके अलावा, दोनों के पास अलग-अलग लक्ष्य हैं: Object.create बस किसी अन्य से विरासत प्राप्त करने वाला ऑब्जेक्ट बनाता है, जबकि newभी एक कन्स्ट्रक्टर फ़ंक्शन का आह्वान करता है। उचित क्या है का प्रयोग करें।

आपके मामले में आप RestModel.prototypeModel.prototype से विरासत प्राप्त करना चाहते हैं। Object.create (या इसके शिम), तो सही तरीका है क्योंकि आप एक) एक नया उदाहरण (दृष्टांत एक new Model) बनाने के लिए नहीं करना चाहते हैं और ख) मॉडल निर्माता कॉल करने के लिए नहीं करना चाहती:

RestModel.prototype = Object.create(Model.prototype); 

हैं आप RestModels पर मॉडल कन्स्ट्रक्टर को कॉल करना चाहते हैं, जिसका प्रोटोटाइप से कोई लेना देना नहीं है। उस के लिए call() या apply() का उपयोग करें:

function RestModel() { 
    Model.call(this); // apply Model's constructor on the new object 
    ... 
} 
+0

उस मामले में 'ऑब्जेक्ट। क्रेते' बेहतर क्यों है? अगर मैं कन्स्ट्रक्टर का भी समर्थन करना चाहता हूं तो क्या होगा? और यह कि कन्स्ट्रक्टर को 'रेस्टमोडेल' और 'मॉडल' दोनों में बुलाया जाता है (यदि मैं 'रेस्टमोडेल' बना देता हूं)। मैं आमतौर पर एक सी # देव हूं, इसलिए मुझे वास्तव में अंतर नहीं मिलता है। मैं बेस प्रोटोटाइप को परिभाषित करना चाहता हूं और एक कन्स्ट्रक्टर का उपयोग करना चाहता हूं, लेकिन मुझे समझ में नहीं आता कि मैं दोनों कैसे प्राप्त करता हूं? – jgauffin

+1

मुझे लगता है कि यह उत्तर * "उचित क्या है इसका उपयोग करें" के साथ यह बताता है। * कभी-कभी आप कन्स्ट्रक्टर में तर्क चाहते हैं, कभी-कभी नहीं। +1 –

10

जावास्क्रिप्ट एक OOP प्रोटोटाइप और नहीं वर्गों के आधार पर भाषा है। यह उन सभी भ्रमों में से एक है जो आप आसपास देख सकते हैं: बहुत से डेवलपर जेएस का उपयोग करते हैं क्योंकि यह कक्षा-आधारित था।

इसलिए, आप कई पुस्तकालयों को देख सकते हैं जो जेएस में कक्षा-आधारित भाषा के प्रतिमान का उपयोग करने का प्रयास कर रहे हैं।

इसके अतिरिक्त, जेएस में कुछ लक्षणों की कमी है जो विरासत, प्रोटोटाइप-आधारित, दर्दनाक बनाता है। उदाहरण के लिए, Object.create से पहले किसी अन्य ऑब्जेक्ट से ऑब्जेक्ट बनाने का कोई तरीका नहीं था (जैसे ओओपी प्रोटोटाइप-आधारित भाषा करना चाहिए), लेकिन केवल function का उपयोग कन्स्ट्रक्टर के रूप में करना है।

और इसी कारण से, आप कई पुस्तकालयों को देख सकते हैं जो भाषा को "ठीक करने" की कोशिश कर रहे हैं, हर कोई अपने तरीके से।

तो, आपका भ्रम सामान्य है। मान लें कि, "आधिकारिक" तरीका prototype संपत्ति, function एस कन्स्ट्रक्टर के रूप में उपयोग किया जाता है, और Object.create ऑब्जेक्ट के इंस्टेंस से बनाने के लिए उपयोग किया जाता है। हालांकि, जैसा ऊपर बताया गया है, कुछ मामलों में कोड वर्बोज़ है या इसमें कार्यक्षमता की कमी है, इसलिए इस प्रक्रिया को अक्सर किसी तरह से लपेटा जाता है, और फिर यह व्यक्तिगत स्वाद का विषय बन जाता है।

क्योंकि आप मॉडल के बारे में बात कर रहे हैं, तो आप Backbone's Model पर एक नज़र डाल सकते हैं और देख सकते हैं कि यह दृष्टिकोण आपको फिट करता है या नहीं।

अद्यतन:

function Model() { 
    this.foo = "foo"; 
    this.array = []; 
} 

Model.prototype.foo = ""; 
Model.prototype.array = null; 
Model.prototype.doNothing = function() {}; 

function RestModel() { 
    this.bar = "bar"; 
} 

RestModel.prototype = new Model; 
RestModel.prototype.bar = "" 

var myModel = new RestModel(); 

अब, यहाँ मुद्दों:

  1. निर्माता कुछ उदाहरण मुझे आशा है कि आपकी मदद करता है स्पष्ट करने के लिए, यहाँ पुराने स्कूल विरासत रास्ता new का उपयोग कर देने के लिए Model को एक बार कहा जाता है, केवल तभी जब RestModel.prototype सेट किया गया है। इसलिए, प्रत्येक RestModel उदाहरण के लिए foo संपत्ति "foo" होगी।
  2. न केवल वह, लेकिन सभीRestModel उदाहरण this.array संपत्ति में एक ही सरणी का एक ही उदाहरण साझा करेंगे। यदि आप सीधे Model का उदाहरण बनाते हैं, तो आपके पास प्रत्येक उदाहरण के लिए सरणी का एक नया उदाहरण है।
  3. myModel.constructor के बजाय Model है। ऐसा इसलिए है क्योंकि हम को Model के नए उदाहरण के साथ ओवरराइड करते हैं, जिसमें constructorModel के बराबर है।
  4. यदि आप RestModel का नया उदाहरण कन्स्ट्रक्टर को आलसी कॉल के साथ रखना चाहते हैं, तो संभव नहीं है।

मुझे लगता है कि मुख्य बिंदु हैं, बेशक वे केवल एकमात्र नहीं हैं। तो, उन मुद्दों को कैसे हल करें? जैसा कि मैंने कहा, बहुत से लोग पहले से ही ऐसा कर चुके हैं, और वे शब्दशः को सीमित करने के लिए पुस्तकालय और ढांचे को भी बनाते हैं। हालांकि, एक विचार है करने के लिए:

function Model() { 
    this.foo = "foo"; 
    this.array = []; 
} 

Model.prototype.foo = ""; 
Model.prototype.array = null; 
Model.prototype.doNothing = function() {}; 

function RestModel() { 
    Model.call(this); 

    this.bar = "bar"; 
} 

RestModel.prototype = Object.create(Model.prototype); 
RestModel.prototype.constructor = RestModel; 
RestModel.prototype.bar = "" 

var myModel = new RestModel(); 

// for lazy constructor call 
var anotherModel = Object.create(RestModel.prototype); 

RestModel.call(anotherModel); 

सूचना आप ऐसा कर सकते आप prototype या function निर्माता के रूप में उपयोग करने के लिए, Object.create साथ नहीं करना चाहते हैं कि:

var Model = { 
    foo: "", 
    array: null, 
    doNothing: function() {} 
} 

var RestModel = Object.create(Model); 

RestModel.bar = ""; 

var myModel = Object.create(RestModel); 

// Assuming you have to set some default values 
initialize(RestModel); 

या:

var Model = { 
    foo: "", 
    array: null, 
    doNothing: function() {}, 

    init : function() { 
     this.foo = "foo"; 
     this.array = []; 
    }, 
} 

var RestModel = Object.create(Model); 

RestModel.bar = ""; 
RestModel.init = function() { 
    Model.init.call(this); 

    this.bar = "bar"; 
} 

var myModel = Object.create(RestModel); 

myModel.init(); 

उस स्थिति में आप मूल रूप से निर्माता का नकल करते हैं। आप descriptor से Object.create (docs देखें) को भी पास कर सकते हैं लेकिन यह अधिक वर्बोज़ बन जाता है। अधिकांश लोग extend फ़ंक्शन या विधि का उपयोग करते हैं (जैसा कि आपने शायद बैकबोन उदाहरण में देखा है)।

उम्मीद है कि यह मदद करता है!

+0

आप किस उदाहरण का सुझाव देते हैं जिसका मैं उपयोग करता हूं? – jgauffin

+0

उनमें से सभी मान्य हैं, लेकिन एक रूप में या दूसरे में वे वर्बोज़ बन जाएंगे। यदि आप 'RestModel' में कई नई गुण या उदाहरण के लिए विधियां हैं तो आप इमेजिंग कर सकते हैं। जब मैंने कहा कि जेएस में अभी भी कुछ कमी है तो मैं यही बात कर रहा था। शब्दकोष को हटाने के लिए, या आप किसी तृतीय पक्ष पुस्तकालयों का उपयोग करने का निर्णय लेते हैं, या आप ऐसा करने के लिए उपयोगिता कार्यों के जोड़ बनाते हैं। मैं शुद्ध 'नया' दृष्टिकोण (पहला) से बचूंगा, और सिर्फ 2 या 3 के लिए तय किया गया है, यह निर्भर करता है कि यदि आप "वर्ग" जैसा दिखते हैं (तो दूसरा) या नहीं (3))। – ZER0

संबंधित मुद्दे