2012-04-28 13 views
6

के बीच का अंतर मुझे लगता है कि अंतर मेरे सिर पर क्लिक किया गया है, लेकिन मैं बस यह सुनिश्चित करना चाहता हूं।जावास्क्रिप्ट में, 'ऑब्जेक्ट.क्रेट' और 'नया'

डगलस Crockford पेज Prototypal Inheritance in JavaScript पर, वे कहते हैं

एक मूलरूप प्रणाली में, वस्तुओं वस्तुओं से प्राप्त करती हैं। जावास्क्रिप्ट, हालांकि, उस ऑपरेटर की कमी है जो उस ऑपरेशन को निष्पादित करता है। इसके बजाए में एक नया ऑपरेटर है, जैसे कि नया एफ() एक नई वस्तु उत्पन्न करता है जो f.prototype से विरासत प्राप्त करता है।

मुझे वास्तव में समझ में नहीं आया कि वह उस वाक्य में क्या कहने की कोशिश कर रहा था इसलिए मैंने कुछ परीक्षण किए। ऐसा लगता है कि मुख्य अंतर यह है कि यदि मैं शुद्ध प्रोटोटाइप सिस्टम में किसी अन्य ऑब्जेक्ट के आधार पर ऑब्जेक्ट बनाता हूं, तो सभी मूल अभिभावक सदस्यों को नई वस्तु के प्रोटोटाइप पर होना चाहिए, न कि नई ऑब्जेक्ट पर।

var Person = function(name, age) { 
     this.name = name; 
     this.age = age; 
} 
Person.prototype.toString = function(){return this.name + ', ' + this.age}; 

// The old way... 
var jim = new Person("Jim",13); 
for (n in jim) { 
    if (jim.hasOwnProperty(n)) { 
     console.log(n); 
    } 
} 
// This will output 'name' and 'age'. 

// The pure way... 
var tim = Object.create(new Person("Tim",14)); 
for (n in tim) { 
    if (tim.hasOwnProperty(n)) { 
     console.log(n); 
    } 
} 
// This will output nothing because all the members belong to the prototype. 
// If I remove the hasOwnProperty check then 'name' and 'age' will be output. 

मेरी समझ सही है कि अंतर केवल स्पष्ट हो जाता है जब वस्तु पर ही सदस्यों के लिए परीक्षण:

यहाँ परीक्षण है?

+3

देखें http://stackoverflow.com/questions/4166616/understanding-the-difference-between-object-create-and-new-somefunction-in-j –

+0

मैंने कल उस प्रश्न को देखा था, मुझे लगता है, लेकिन जवाब मुझे स्पष्ट नहीं था। अब मैंने अपने परीक्षण किए हैं और मेरा प्रश्न टाइप किया है, यह स्पष्ट है! – Jules

उत्तर

3

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

var Person = function(name, age) { 
    this.name = name; 
    this.age = age; 
} 
Person.prototype.name = null; //default value if you don't init in ctor 
Person.prototype.age = null; 
Person.prototype.gender = "male"; 
Person.prototype.toString = function(){return this.name + ', ' + this.age;}; 

इस मामले में, इस वर्ग का एक उदाहरण के गुणों से अधिक पुनरावृत्ति, के रूप में आप अपने उदाहरण में करते हैं, 'लिंग' प्रॉपर्टी के लिए कोई उत्पादन उत्पन्न होगा।

संपादित करें 1: निर्माता में नाम और उम्र के काम गुण सामने प्रस्तुत करें hasOwnProperty द्वारा (मुझे इस की याद दिलाने के लिए धन्यवाद @matt) से करते हैं। असाइन किए गए लिंग प्रॉपर्टी तब तक दिखाई नहीं देगी जब तक कि कोई इसे उदाहरण पर सेट न करे।

संपादित करें 2: आगे यह करने के लिए जोड़ने के लिए, मैं एक विकल्प के वंशानुक्रम स्वरूप पेश - एक है कि मैं व्यक्तिगत रूप से बहुत बड़ी परियोजनाओं के लिए इस्तेमाल किया है:

var inherits = function(childCtor, parentCtor) { 
    function tempCtor() {}; 
    tempCtor.prototype = parentCtor.prototype; 
    childCtor.superclass = parentCtor.prototype; 
    childCtor.prototype = new tempCtor(); 
    childCtor.prototype.constructor = childCtor; 
}; 

var Person = function(name){ 
    this.name = name; 
} 
Person.prototype.name = ""; 
Person.prototype.toString = function(){ 
    return "My name is " + this.name; 
} 

var OldPerson = function(name, age){ 
    OldPerson.superclass.constructor.call(this); 
    this.age = age 
}; 
inherits(OldPerson, Person); 
OldPerson.prototype.age = 0; 
OldPerson.prototype.toString = function(){ 
    var oldString = OldPerson.superclass.toString.call(this); 
    return oldString + " and my age is " + this.age; 
} 

यह एक छोटा मोड़ के साथ एक बहुत ही आम पैटर्न है - अभिभावक वर्ग बच्चे को "सुपरक्लास" संपत्ति के माध्यम से संलग्न किया जाता है जिससे आप बच्चे द्वारा ओवरराइड विधियों/संपत्तियों तक पहुंच सकते हैं। तकनीकी रूप से, आप OldPerson.superclass को Person के साथ प्रतिस्थापित कर सकते हैं, हालांकि यह आदर्श नहीं है। यदि आपने कभी भी ओल्डपर्सन को व्यक्ति के अलावा किसी अन्य वर्ग से प्राप्त करने के लिए बदल दिया है, तो आपको व्यक्ति के सभी संदर्भों को भी अपडेट करना होगा।

संपादित करें 3: बस इस चक्र पूरा लाने के लिए, यहाँ जो बिल्कुल वैसा ही Object.create और कार्यों का लाभ लेता है के रूप में मैं पहले से वर्णित "inherits" समारोह का एक संस्करण है:

var inherits = function(childCtor, parentCtor) { 
    childCtor.prototype = Object.create(parentCtor.prototype); 
    childCtor.superclass = parentCtor.prototype; 
}; 
3

संपादित करें : यह उत्तर मूल रूप से @ जोर्डनपॉल के उत्तर की प्रतिक्रिया थी, जिसे उन्होंने तब से सही किया है।मैं अपने जवाब के भाग प्रोटोटाइप गुण और उदाहरण गुणों के बीच महत्वपूर्ण अंतर समझाने में मदद करता है कि छोड़ देंगे:

कुछ मामलों में, गुण सभी उदाहरणों के बीच साझा कर रहे हैं और आप जब गुण घोषणा कर रहे बहुत सावधान होने की जरूरत है प्रोटोटाइप पर। अगर आप या तो Object.create या new उपयोग कर एक नया व्यक्ति उदाहरण बनाने

Person.prototype.favoriteColors = []; //Do not do this!

अब, जैसा कि आप उम्मीद कर सकते हैं यह काम नहीं करता ...

var jim = new Person("Jim",13); 
jim.favoriteColors.push('red'); 
var tim = new Person("Tim",14); 
tim.favoriteColors.push('blue'); 

console.log(tim.favoriteColors); //outputs an array containing red AND blue! 

यह नहीं करता है ': इस उदाहरण पर विचार टी का मतलब है कि आप प्रोटोटाइप पर कभी भी संपत्ति घोषित नहीं कर सकते हैं, लेकिन यदि आप करते हैं, तो आप और आपके डेवलपर जो आपके कोड पर काम करते हैं, इस पतन के बारे में जागरूक होने की आवश्यकता है। इस तरह के मामले में, यदि आप किसी भी कारण से प्रोटोटाइप पर गुण की घोषणा पसंद करते हैं, तो आप कर सकता है:

Person.prototype.favoriteColors = null

और निर्माता में एक खाली सरणी के लिए इसे प्रारंभ:

var Person = function(name, age) { 
    ... 
    this.favoriteColors = []; 
} 

सामान्य विधि इस विधि का उपयोग करते समय यह है कि सरल शाब्दिक गुणों (तारों, संख्याओं, बूलियन) के लिए डिफ़ॉल्ट मान सीधे प्रोटोटाइप पर सेट किए जा सकते हैं, लेकिन ऑब्जेक्ट (एरे और तिथियों सहित) से प्राप्त किसी भी संपत्ति को शून्य पर सेट किया जाना चाहिए और फिर प्रारंभ किया जाना चाहिए निर्माता में।

सुरक्षित तरीका केवल प्रोटोटाइप पर विधियों की घोषणा करना है, और हमेशा निर्माता में गुण घोषित करना है।

वैसे भी, सवाल Object.create के बारे में था ...

पहले Object.create के लिए पारित तर्क नया उदाहरण के प्रोटोटाइप के रूप में स्थापित किया जाएगा। एक बेहतर उपयोग होगा:

var person = { 
    initialize: function(name, age) { 
     this.name = name; 
     this.age = age; 
     return this; 
    }, 

    toString: function() { 
     return this.name + ', ' + this.age; 
    } 
}; 

var tim = Object.create(person).initialize("Tim",14); 

अब आउटपुट आपके पहले उदाहरण जैसा ही होगा।

जैसा कि आप देख सकते हैं, यह जावास्क्रिप्ट में ओओपी की अधिक शास्त्रीय शैली से एक अलग दार्शनिक दृष्टिकोण है। Object.create के साथ, कन्स्ट्रक्टर के बजाए मौजूदा ऑब्जेक्ट्स से नई ऑब्जेक्ट्स बनाने पर जोर दिया जाता है। प्रारंभ तब एक अलग कदम बन जाता है।

व्यक्तिगत रूप से मेरे पास ऑब्जेक्ट.क्रेट दृष्टिकोण के बारे में मिश्रित भावनाएं हैं; दूसरे पैरामीटर की वजह से विरासत के लिए यह बहुत अच्छा है, जिसका उपयोग आप मौजूदा प्रोटोटाइप में अतिरिक्त गुण जोड़ने के लिए कर सकते हैं, लेकिन यह भी अधिक वर्बोज़ है और यह जांच करता है कि चेक अब काम नहीं करते हैं (इस उदाहरण में विकल्प person.isPrototypeOf(tim) जांचना होगा) ।

मुख्य कारण मैं कहता हूँ Object.create वर्बोज़ है दूसरा पैरामीटर की वजह से है, लेकिन वहाँ कुछ उपयोगी पुस्तकालयों वहाँ बाहर है कि पता कर रहे हैं:

https://github.com/Gozala/selfish

https://github.com/Raynos/pd

(और दूसरों)

मुझे उम्मीद है कि भ्रमित करने से ज्यादा प्रबुद्ध था!

+1

मैंने पारंपरिक प्रोटोटाइप विरासत विधि के बाद विरासत में मदद करने के लिए एक * बहुत * सरल लाइब्रेरी लिखी है, लेकिन यह "वर्ग": https://github.com/mbrowne/simpleoo को विस्तारित करते समय ऑब्जेक्ट.क्रेट का उपयोग करता है। जेएस –

+0

यूप, 'class.prototype.property = []' pitfall खुद को गिर गया। मैंने अपनी मूल पोस्ट को थोड़ी अधिक जानकारी के साथ अपडेट किया है - शायद आपने पहले इस पैटर्न को देखा है। – jordancpaul

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