2012-10-18 11 views
5

बस जब मैंने सोचा कि मैं जे एस पता लगा था, मैं इस पर लटका दिया हो:instanced वस्तु और गुण है कि संदर्भ हैं

function Obj() { 
    console.log('x: %s, o.x: %s', this.x++, this.o.x++); 
}  
Obj.prototype.x = 1; 
Obj.prototype.o = {x: 1}; 

अपेक्षित:

> new Obj 
x: 1, o.x: 1 
> new Obj 
x: 1, o.x: 1 
> new Obj 
x: 1, o.x: 1 

वास्तविक:

> new Obj 
x: 1, o.x: 1 
> new Obj 
x: 1, o.x: 2 
> new Obj 
x: 1, o.x: 3 

तो, ऐसा लगता है कि यदि प्रोटोटाइप प्रॉपर्टी एक संदर्भ प्रकार है, तो यह सभी मामलों में साझा की जाती है, फिर भी यदि यह एक गैर-संदर्भ प्रकार है यह प्रत्येक उदाहरण के लिए पुन: प्रारंभ किया गया है; इस परिकल्पना की पुष्टि करने के लिए, मैंने कुछ अन्य प्रकारों का परीक्षण किया, जैसे string (जो number जैसा व्यवहार करता है) और array (जो object जैसा व्यवहार करता है)।

मैं निर्धारित किया है कि अगर मैं ctor में वस्तु संपत्ति reinitialize, इस तरह है कि मैं इस चूक से बचने कर सकते हैं:

function Obj() { 
    this.o = {x: 1}; 
} 
सिर्फ वास्तव में अपरंपरागत लगता है कौन सा (कि मैं मैन्युअल रूप से गुण reinitialize करने के लिए आवश्यक होगी

लेकिन केवल अगर वे एक संदर्भ वस्तु हैं)।

क्या कोई भी क्या हो रहा है पर कुछ प्रकाश डाल सकता है?

+1

'(नया ओब्जे) .o === (नया ओब्जे) .o' - [विरासत] गुण सभी एक ही ऑब्जेक्ट को इंगित करते हैं, जिसका 'x' प्रॉपर्टी आप बढ़ती है। – Bergi

+0

* ".. जैसे स्ट्रिंग (जो संख्या की तरह व्यवहार करती है) और सरणी (जो ऑब्जेक्ट की तरह व्यवहार करती है) .." * अच्छी तरह से, प्राइमेटिव्स को मूल्य (तार, संख्या, बूलियन) द्वारा कॉपी किया जाता है जबकि ऑब्जेक्ट्स (हाँ, 'सरणी' एक है वस्तु भी) संदर्भ द्वारा प्रतिलिपि बनाई गई हैं। बात यह है कि जब आप 'ओ' ऑब्जेक्ट की 'x' प्रॉपर्टी को संशोधित करते हैं, तो आप प्रोटोटाइप श्रृंखला में उसी' ओ 'ऑब्जेक्ट के संदर्भ को संशोधित कर रहे हैं। –

उत्तर

3

इस तरह से सोचें। आप उस ऑब्जेक्ट को संशोधित करने जा रहे हैं जिस पर आप काम कर रहे हैं, भले ही मूल्य कहां से आता है।

आप पहली बार के लिए ऐसा करते हैं जब:

this.x++; 

यह Obj.prototype.x से x का मूल्य हो रही है क्योंकि वहाँ this वस्तु पर कोई x संपत्ति सीधे था, फिर भी ++ अब भी है पर कामthis ऑब्जेक्ट, इसलिए उस ऑब्जेक्ट पर मान सेट किया गया है। यह मान अब भविष्य में संशोधन के लिए सीधे उदाहरण पर है। (जब तक प्रत्यक्ष संपत्ति delete घ है prototype.x आच्छादित है।)

हालांकि, जब आप यह करते हैं:

this.o.x++ 

this वस्तु पर ही आपरेशन o के देखने है। चूंकि this पर o संपत्ति नहीं है, तो आपको Obj.prototype.o पर संग्रहीत ऑब्जेक्ट का संदर्भ प्राप्त होगा। इस बिंदु पर, this ऑब्जेक्ट का कोई वास्तविक संशोधन नहीं है।

संदर्भ लौटने के बाद, आप Obj.prototype.o ऑब्जेक्ट पर x संपत्ति देखें और इसे संशोधित करें।

तो यह वास्तव में काफी संगत है। this.o.x++ के साथ आपने this पर एक लुकअप किया है, लेकिन कोई उत्परिवर्तन नहीं है। उत्परिवर्तन संदर्भित वस्तु पर है। लेकिन this.x++ के साथ, आप ऑब्जेक्ट को सीधे म्यूट कर रहे हैं।


तो हाँ, जब तक आप अपने संदर्भ के प्रकार के निर्माता से बनाए गए सभी उदाहरणों के बीच साझा किया जाना चाहते हैं, तो आप संदर्भ प्रकार सीधे उदाहरणों पर और .prototype पर नहीं रखना चाहिए।

+0

धन्यवाद! आपने पुष्टि की कि मुझे क्या संदेह है (हालांकि आपने इसे बेहतर बताया है)। – ken

+0

आपका स्वागत है। –

0

मुझे लगता है कि पहले जवाब में इसका सारांश है, लेकिन मैं थोड़ा अलग कोण से जवाब दे रहा हूं।

किसी ऑब्जेक्ट को असाइन करने के संबंध में इसे समझने की कुंजी ऑब्जेक्ट व्यवहार है।

यदि कोई आवृत्ति संपत्ति नहीं है तो लुकअप प्रोटोटाइप पर वापस आते हैं। हमेशा।

असाइनमेंट, हालांकि, हर बार एक नई इंस्टेंस संपत्ति स्वत: बना देगा। यह वास्तव में कोई फर्क नहीं पड़ता कि आप एक नई संदर्भ संपत्ति के लिए एक संदर्भ संदर्भ प्रोटोटाइप संपत्ति असाइन करते हैं क्योंकि वे दोनों एक ही चीज़ के लिए पॉइंटर्स हैं। और यदि आप जगह-जगह बदलते हैं, तो कोई नई घटना संपत्ति या तो बनाई जाएगी।

function Obj(){ 
    //this.refArr resolves to what's in the prototype and that's what we change 
    this.refArr.push(1); 

    //now copy sliceArray and assign a new but identical array 
    this.sliceArray = this.sliceArray.slice(0); 

    //no length increase would mean a new instance property is created 
    //... and then the assigment took place. 
    this.sliceArray.push(1); 
    console.log('ref:'+this.refArr.length +', sliceArray:'+this.sliceArray.length); 
} 
Obj.prototype.refArr = []; 
Obj.prototype.sliceArray = []; 
new Obj; new Obj; 
//ref:1, sliceArray:1 
//ref:2, sliceArray:1 

और यह अनिवार्य रूप से आप जो कर रहे हैं उसमें अंतर है। this.x = this.x + 1 एक नई संपत्ति बनाता है। चूंकि आप this.constructor.prototype.o की संपत्ति को असाइन करते हैं, इसलिए कोई नई संपत्ति नहीं बनाई जाती है। यदि आप वृद्धि करते हैं और फिर इसे सौंपते हैं। तो इससे कोई फर्क नहीं पड़ता, क्योंकि प्रोटोटाइप और नया प्रॉपर्टी संस्करण केवल उसी ऑब्जेक्ट पर इंगित करेगा।

+1

बेशक 'this.refArr = this.refArr; 'एक नई संपत्ति बनाएगा, फिर भी यह पहले से विरासत वाली संपत्ति के समान सरणी को इंगित करता है। आप 'Obj.prototype.refArr' – Bergi

+0

आह बदलकर आसानी से जांच सकते हैं, आप सही हैं। मैंने परीक्षण में हैऑनप्रोपर्टी का दुरुपयोग किया। फिक्सिंग। –

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