जावास्क्रिप्ट वंशानुक्रम: Object.create बनाम नया


123

जावास्क्रिप्ट में इन दो उदाहरणों के बीच अंतर क्या है:

शर्त:

function SomeBaseClass(){
}

SomeBaseClass.prototype = {
    doThis : function(){
    },

    doThat : function(){
    }
}

विरासत उदाहरण एक का उपयोग कर Object.create:

function MyClass(){
}

MyClass.prototype = Object.create(SomeBaseClass.prototype);

नए कीवर्ड का उपयोग करके इनहेरिटेंस उदाहरण B

function MyClass(){
}

MyClass.prototype = new SomeBaseClass();

दोनों उदाहरण एक ही काम करते प्रतीत होते हैं। आपने एक को कब चुना?

एक अतिरिक्त प्रश्न: नीचे दिए गए लिंक (पंक्ति 15) में कोड पर विचार करें, जहां फ़ंक्शन के स्वयं के निर्माण का एक संदर्भ प्रोटोटाइप में संग्रहीत है। यह क्यों उपयोगी है?

https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js

उद्धरण (यदि आप लिंक नहीं खोलना चाहते हैं):

THREE.ImageLoader.prototype = {

    constructor: THREE.ImageLoader
}

23
क्यों इस बिल्ली को डुप्लिकेट के रूप में चिह्नित किया गया है ?! अन्य सवाल, और जवाब, भी उल्लेख नहीं है Object.create। यह एक गलती है, और इसे फिर से खोलना चाहिए।
स्कॉट Rippey

2
यदि कुछ भी हो, तो यह stackoverflow.com/questions/4166616/…
स्कॉट रिप्पे

1
उस टिप्पणी पर 13 वोट और अभी भी फिर से खोलना नहीं है ..!
TJ

जवाबों:


111

आपके प्रश्न में आपने उल्लेख किया है कि Both examples seem to do the same thing, यह बिल्कुल सच नहीं है, क्योंकि

आपका पहला उदाहरण

function SomeBaseClass(){...}
SomeBaseClass.prototype = {
    doThis : function(){...},
    doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);

इस उदाहरण में, तुम सिर्फ विरासत में कर रहे हैं SomeBaseClass' prototype, लेकिन क्या अगर आप अपने में कोई संपत्ति है, SomeBaseClassकी तरह

function SomeBaseClass(){ 
    this.publicProperty='SomeValue'; 
}

और यदि आप इसका उपयोग करते हैं

var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);​

objवस्तु के लिए नहीं होगा publicPropertyकी तरह संपत्ति इस उदाहरण में

आपका दूसरा उदाहरण

MyClass.prototype = new SomeBaseClass();

यह constructorफ़ंक्शन निष्पादित कर रहा है, एक उदाहरण बना रहा है SomeBaseClassऔर संपूर्ण SomeBaseClassऑब्जेक्ट को इनहेरिट कर रहा है। इसलिए, यदि आप उपयोग करते हैं

    var obj=new MyClass();
    console.log(obj.publicProperty); // SomeValue
    console.log(obj);​

इस मामले में इसकी publicPropertyसंपत्ति भी इस उदाहरण कीobj तरह वस्तु के लिए उपलब्ध है ।

चूंकि Object.createकुछ पुराने ब्राउज़रों में यह उपलब्ध नहीं है, ऐसे में आप इसका उपयोग कर सकते हैं

if(!Object.create)
{
    Object.create=function(o){
        function F(){}
        F.prototype=o;
        return new F();
    }
}

उपरोक्त कोड बस Object.createफ़ंक्शन जोड़ता है यदि यह उपलब्ध नहीं है तो आप Object.createफ़ंक्शन का उपयोग कर सकते हैं और मुझे लगता है कि ऊपर दिए गए कोड का वर्णन करता है कि Object.createवास्तव में क्या करता है। आशा है कि यह किसी तरह से मदद करेगा।


6
हाय शेख। इस पर आपके प्रयासों के लिए धन्यवाद। हां, अंतर यह है कि कंस्ट्रक्टर को दूसरे उदाहरण में चलाया जाता है लेकिन पहले में नहीं। (जो मेरे मामले में वांछनीय है)। अपरिभाषित सार्वजनिक संपत्ति के बारे में जो सुपर कार्यान्वयन से विरासत में नहीं मिली है, आपको बस बच्चे के निर्माता में सुपर को कॉल करने की आवश्यकता है: SomeBaseClass.call (यह)। इस
फिडेल की

मैं किसी भी पुस्तकालयों / चौखटे का उपयोग किए बिना जेएस में उचित विरासत के एक सुपर सरल तरीके की तलाश कर रहा हूं। मुझे लगता है कि यह उदाहरण (ऊपर मेरी फ़ेल्ड में) आधुनिक ब्राउज़रों के लिए सबसे अच्छा तरीका है। शायद Object.Create polyfill विरासत ब्राउज़रों के लिए समर्थन जोड़ सकता है?
क्रिसरिट

मूल रूप से संक्षेप में, यदि आप .prototyp = नया करते हैं, तो आप बेस क्लास में आपके द्वारा असाइन किए गए किसी भी मान को विरासत में दे रहे हैं, और जब आप ऑब्जेक्ट करते हैं। आप केवल आधार वर्ग में प्रोटोटाइप पर क्या है विरासत में मिला है, है ना?
davidjnelson

Doest इस "MyClass.prototype = new SomeBaseClass ()" का अर्थ है कि जब MyClass का उदाहरण अभी तक नहीं बनाया गया है, तो SomeBaseClass का नया उदाहरण बनाया गया है?

नहीं, केवल जब आप मुख्य वस्तु बनाते हैं तो प्रोटोटाइप उसी पर सेट होता है SomeBaseClass
अल्फा

39

दोनों उदाहरण एक ही काम करते प्रतीत होते हैं।

आपके मामले में यह सच है।

आपने एक को कब चुना?

जब SomeBaseClassएक फ़ंक्शन बॉडी होती है, तो यह newकीवर्ड के साथ निष्पादित हो जाएगी । यह आमतौर पर इरादा नहीं है - आप केवल प्रोटोटाइप श्रृंखला स्थापित करना चाहते हैं। कुछ मामलों में यह गंभीर मुद्दों का कारण भी बन सकता है क्योंकि आप वास्तव में एक वस्तु को त्वरित करते हैं, जिनके निजी-स्कोप किए गए चर सभी MyClassउदाहरणों द्वारा साझा किए जाते हैं क्योंकि वे एक ही विशेषाधिकार प्राप्त तरीकों को प्राप्त करते हैं। अन्य दुष्प्रभाव कल्पना करने योग्य हैं।

इसलिए, आपको आम तौर पर पसंद करना चाहिए Object.create। फिर भी, यह कुछ विरासत ब्राउज़रों में समर्थित नहीं है; यही कारण है कि आप new-approach को बहुत अधिक बार देखते हैं क्योंकि यह अक्सर (स्पष्ट) नुकसान नहीं करता है। इस जवाब पर भी एक नजर डालिए


यह सबसे अच्छा जवाब है, अच्छी तरह से समझाया गया
2

8

अंतर स्पष्ट हो जाता है यदि आप इसका उपयोग करते हैं Object.create()जैसा कि इसका इरादा है। दरअसल, यह prototypeआपके कोड से शब्द को पूरी तरह से छिपा देता है, यह हुड के तहत काम करेगा। का उपयोग करते हुए Object.create(), हम जैसे जा सकते हैं

var base =  {
    doThis : function(){
    },

    doThat : function(){
    }
};

और फिर हम इससे अन्य वस्तुओं का विस्तार / विरासत कर सकते हैं

var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally

तो यह एक और अवधारणा है, विरासत का एक अधिक "वस्तु उन्मुख" तरीका है। Object.create()उदाहरण के लिए बॉक्स का कोई "निर्माता फ़ंक्शन" नहीं है । लेकिन निश्चित रूप से आप एक स्व-परिभाषित कंस्ट्रक्टर फ़ंक्शन को केवल बना और कॉल कर सकते हैं उन वस्तुओं के भीतर हैं।

उपयोग करने के लिए एक तर्क Object.create()यह है कि Javascripts डिफ़ॉल्ट तरीके का उपयोग करने की तुलना में अन्य वस्तुओं से मिश्रण / * विरासत * प्राप्त करना अधिक स्वाभाविक लग सकता है ।


7
Object.createवास्तव में शास्त्रीय दृष्टिकोण को प्रतिस्थापित नहीं कर सकता है newजब एक निर्माण कार्य की आवश्यकता होती है
बर्गी

1
यह निश्चित रूप से @Bergi कर सकते हैं। इस ब्लॉग पोस्ट को देखो: davidwalsh.name/javascript-objects-deconstruction । आप Object.create () के लिए दूसरे पैरामीटर के रूप में एक इनिशियलाइज़ेशन ऑब्जेक्ट भी पास कर सकते हैं।
लोकलपीसीग्युय

@LocalPCGuy: नहीं, यह नहीं हो सकता है, क्योंकि Object.createफ़ंक्शन को कॉल नहीं करता है जो क्लोजर बनाने के लिए आवश्यक होगा। बेशक, Object.createआप initअपनी वस्तुओं पर एक विधि डाल सकते हैं और तुरंत कॉल कर सकते हैं और यह शायद वापस भी आ thisजाए ताकि आपको संक्षिप्त वाक्यविन्यास मिल जाए - लेकिन रुकिए, यह एक रचनाकार है।
बर्गी

1
एक इनिट फ़ंक्शन को कॉल करना एक कंस्ट्रक्टर के समान काम करता है, लेकिन यह एक कंस्ट्रक्टर नहीं है। और वह विधि आपको शास्त्रीय दृष्टिकोण को Object.create के साथ बदलने की अनुमति देती है। और ऑब्जेक्ट लिंकेज का मानसिक मॉडल 'नए' के ​​माध्यम से निर्मित की तुलना में बहुत सरल है।
लोकलPCGuy

खैर, मेरा मानसिक मॉडल new"ऑब्जेक्ट लिंकेज" का उपयोग करता है, इसलिए इसमें बहुत अंतर नहीं है। वास्तव में, केवल दो चीजें हैं: .constructorकहा जाता है .init, और उस फ़ंक्शन में .prototypeआपके प्रोटोटाइप ऑब्जेक्ट पर वापस इंगित करने वाली संपत्ति नहीं है । बाकी सिर्फ वाक्य रचना है - और मुझे पसंद करते हैं new Xअधिक Object.create(x).init()
बर्गी

0

मैं जावा स्क्रिप्ट का विशेषज्ञ नहीं हूं, लेकिन यहां "Object.create" और "new" के बीच अंतर को समझने के लिए एक सरल उदाहरण है।

चरण 1: कुछ गुणों और कार्यों के साथ मूल कार्य बनाएँ।

function Person() {

this.name = 'venkat';

this.address = 'dallas';

this.mobile='xxxxxxxxxx'

}

Person.prototype.func1 = function () {

    return this.name + this.address;
}

चरण 2: एक बच्चे का फ़ंक्शन (पर्सनालरी) बनाएं जो नए कीवर्ड का उपयोग करके व्यक्ति फ़ंक्शन से ऊपर निकलता है ।

function PersonSalary() {
    Person.call(this);
}
PersonSalary.prototype = new Person();

PersonSalary();

चरण 3: दूसरा चाइल्ड फंक्शन (पर्सोलाइव्स) बनाएं, जो Object.create कीवर्ड का उपयोग करके व्यक्ति के फंक्शन से ऊपर हो ।

function PersonLeaves() {
 Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);


PersonLeaves();

// अब दोनों चाइल्ड फ़ंक्शंस प्रोटोटाइप की जाँच करें।

PersonSalary.prototype
PersonLeaves.prototype

ये दोनों चाइल्ड फ़ंक्शंस पर्सन (पेरेंट फंक्शन) प्रोटोटाइप से लिंक होंगे और इसे ऐक्सेस कर सकते हैं लेकिन अगर आप नए का उपयोग करके चाइल्ड फंक्शन बनाते हैं तो यह सभी पैरेंट प्रॉपर्टीज़ के साथ एक बिलकुल नया ऑब्जेक्ट लौटाएगा जिसकी हमें ज़रूरत नहीं है और जब आप कोई भी बनाते हैं ऑब्जेक्ट या फ़ंक्शन "न्यू" का उपयोग करके उस मूल फ़ंक्शन को निष्पादित किया जाता है जो हम नहीं चाहते हैं।

यहाँ takeaways हैं

अगर आप सिर्फ पैरेंट फंक्शन में कुछ तरीकों को सौंपना चाहते हैं और नहीं चाहते हैं कि Object.create का उपयोग करके एक नया ऑब्जेक्ट बनाया जाए, तो यह सबसे अच्छा तरीका है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.