2012-04-12 10 views
12

मैं डगलस क्रॉकफ़ोर्ड द्वारा "जावास्क्रिप्ट: द गुड पार्ट्स" पढ़ रहा हूं - और यह थोड़ी चरम है, लेकिन मैं जो कुछ कहना चाहता हूं उसके साथ बोर्ड पर हूं।क्रॉकफोर्ड प्रोटोटाइप विरासत - नेस्टेड ऑब्जेक्ट्स के साथ मुद्दे

अध्याय 3 में, वह वस्तुओं की चर्चा और एक बिंदु पर & को सरल बनाने भ्रम/मुद्दों है कि निर्मित 'नई' कीवर्ड के उपयोग से आने के कुछ से बचने के लिए एक पैटर्न (भी found here) बाहर देता है।

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

तो मैं एक परियोजना मैं पर काम कर रहा हूँ में इस का उपयोग कर की कोशिश की है, और जब वस्तुओं है कि नेस्टेड रहते हैं से विरासत के लिए प्रयास कर रहा एक मुद्दा देखा। यदि मैं इस पैटर्न का उपयोग करके विरासत में प्राप्त एक नेस्टेड ऑब्जेक्ट का मान ओवरराइट करता हूं, तो यह प्रोटोटाइप श्रृंखला के सभी तरह से नेस्टेड तत्व को ओवरराइट करता है।

क्रॉकफोर्ड का उदाहरण निम्नलिखित उदाहरण में flatObj जैसा है, जो अच्छी तरह से काम करता है।

मैं कुछ गलत कर रहा हूँ

var flatObj = { 
    firstname: "John", 
    lastname: "Doe", 
    age: 23 
} 
var person1 = Object.create(flatObj); 

var nestObj = { 
    sex: "female", 
    info: { 
     firstname: "Jane", 
     lastname: "Dough", 
     age: 32 
    } 
} 
var person2 = Object.create(nestObj); 

var nestObj2 = { 
    sex: "male", 
    info: { 
     firstname: "Arnold", 
     lastname: "Schwarzenneger", 
     age: 61 
    } 
} 
var person3 = { 
    sex: "male" 
} 
person3.info = Object.create(nestObj2.info); 

// now change the objects: 
person1.age = 69; 
person2.info.age = 96; 
person3.info.age = 0; 

// prototypes should not have changed: 
flatObj.age // 23 
nestObj.info.age // 96 ??? 
nestObj2.info.age // 61 

// now delete properties: 
delete person1.age; 
delete person2.info.age; 
delete person3.info.age; 

// prototypes should not have changed: 
flatObj.age // 23 
nestObj.info.age // undefined ??? 
nestObj2.info.age // 61 

(यह भी एक fiddle पर), या यह इस पद्धति की एक सीमा है: व्यवहार, तथापि, नेस्टेड वस्तुओं के साथ असंगत है?

+0

संबंधित: [जावास्क्रिप्ट ऑब्जेक्ट.क्रेट - विरासत नेस्टेड गुणों को विरासत में रखते हुए] (http://stackoverflow.com/q/3191103/1048572) – Bergi

उत्तर

10

कोई असंगतता नहीं है। बस नेस्टेड ऑब्जेक्ट्स के बारे में मत सोचें: डायरेक्ट किसी ऑब्जेक्ट की प्रॉपर्टी हमेशा इसके प्रोटोटाइप या अपनी संपत्ति पर होती है। यह अप्रासंगिक मक्खन संपत्ति का मूल्य एक आदिम या वस्तु है।

इसलिए, जब आप कर

var parent = { 
    x: {a:0} 
}; 
var child = Object.create(parent); 

child.xparent.x रूप में एक ही वस्तु को संदर्भित किया जाएगा - कि एक {a:0} वस्तु। और जब आप इसकी संपत्ति बदलते हैं:

var prop_val = child.x; // == parent.x 
prop_val.a = 1; 

दोनों प्रभावित होंगे। - लेकिन अभी भी दो अलग अलग

child.x = {a:0}; 
child.x.a = 1; 
parent.x.a; // still 0 

आप क्या कर सकते

child.x = Object.create(parent.x); 
child.x.a = 1; 
delete child.x.a; // (child.x).a == 0, because child.x inherits from parent.x 
delete child.x; // (child).x.a == 0, because child inherits from parent 

जिसका मतलब है कि वे पूरी तरह से स्वतंत्र नहीं हैं: स्वतंत्र रूप से एक "नेस्ट" संपत्ति को बदलने के लिए, आपको पहले एक स्वतंत्र वस्तु बनाने के लिए होगा वस्तुओं।

+0

यह चीजों को थोड़ा सा स्पष्ट करता है - और अब मैं इस मुद्दे को समझता हूं। धन्यवाद :) क्योंकि सभी वस्तुओं संदर्भ हैं ... दुह। इस तरह से अभी भी कम सुविधाजनक। ओह अच्छा। – 1nfiniti

+0

* "ऑब्जेक्ट की सीधी संपत्ति हमेशा या तो अपने प्रोटोटाइप या अपनी संपत्ति पर होती है" * - मेरे लिए एक सीधी संपत्ति का मतलब है कि वस्तुओं की संपत्ति होती है, और इसके प्रोटोटाइप श्रृंखला में से किसी को * अप्रत्यक्ष * कहा जा सकता है। क्या आप समझा सकते हैं कि प्रत्यक्ष संपत्ति से आपका क्या मतलब है, या * अप्रत्यक्ष * संपत्ति क्या है ..? –

+0

@TJ मुझे लगता है कि मैंने "प्रत्यक्ष" शब्द का उपयोग यहां "नेस्टेड" के विपरीत किया है। कहने के लिए एक संपत्ति श्रृंखला में एक स्तर। – Bergi

1

मुझे लगता है कि क्या हो रहा है कि जब आप person2 बनाते हैं, तो इसके बारे में sex और info गुण nestObj में उन लोगों का उल्लेख है। जब आप person2.info का संदर्भ देते हैं, person2info संपत्ति को फिर से परिभाषित नहीं करता है, तो यह प्रोटोटाइप के माध्यम से जाता है और वहां ऑब्जेक्ट को संशोधित करता है।

ऐसा लगता है कि यह करने के लिए "सही" तरीका यह है कि आप person3 बनाते हैं, ताकि ऑब्जेक्ट का अपना info ऑब्जेक्ट संशोधित हो और प्रोटोटाइप तक न जाए।

मैं पुस्तक भी (धीरे-धीरे) पढ़ रहा हूं, इसलिए मैं आपके साथ सहानुभूति व्यक्त करता हूं। :)

1

मैंने उदाहरणों को बदल दिया है ताकि आपको यहां क्या हो रहा है इसका एक बेहतर प्रदर्शन प्रदान किया जा सके।Demo

सबसे पहले हम तीन गुणों के साथ एक वस्तु बनाते हैं; स्ट्रिंग मान वाले एक प्रॉपर्टी के साथ एक संख्या, एक स्ट्रिंग और ऑब्जेक्ट।

फिर हम का उपयोग कर पहले से दूसरी ऑब्जेक्ट बनाते हैं;

var obj1 = { 
    num : 1, 
    str : 'foo', 
    obj : { less: 'more' } 
}; 
var obj2 = Object.create(obj1); 

console.log('[1] obj1:', obj1); 
console.log('[1] obj2:', obj2); 
"[1] obj1:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "foo" 
} 
"[1] obj2:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "foo" 
} 

अच्छा सही लगता है? हमारे पास हमारी पहली वस्तु है और दूसरी प्रतिलिपि बनाई गई वस्तु है।

इतना तेज़ नहीं; चलो देखते हैं कि जब हम पहले ऑब्जेक्ट पर कुछ मान बदलते हैं तो क्या होता है।

obj1.num = 3; 
obj1.str = 'bar'; 
obj1.obj.less = 'less'; 

console.log('[2] obj1:', obj1); 
console.log('[2] obj2:', obj2); 
"[2] obj1:" 
[object Object] { 
    num: 3, 
    obj: [object Object] { 
    less: "less" 
    }, 
    str: "bar" 
} 
"[2] obj2:" 
[object Object] { 
    num: 3, 
    obj: [object Object] { 
    less: "less" 
    }, 
    str: "bar" 
} 

अब फिर से हम परिवर्तन के साथ हमारी पहली वस्तु है, और उस वस्तु की एक प्रति। यहाँ क्या हो रहा है?

चलो जांचें कि ऑब्जेक्ट्स के पास अपनी संपत्ति है या नहीं।

for(var prop in obj1) console.log('[3] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop)); 
for(var prop in obj2) console.log('[3] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop)); 
"[3] obj1.hasOwnProperty(num): true" 
"[3] obj1.hasOwnProperty(str): true" 
"[3] obj1.hasOwnProperty(obj): true" 
"[3] obj2.hasOwnProperty(num): false" 
"[3] obj2.hasOwnProperty(str): false" 
"[3] obj2.hasOwnProperty(obj): false" 

obj1 अपने स्वयं के सभी गुणों की तरह ही हम परिभाषित किया है,, लेकिन obj2 नहीं करता है।

क्या होता है जब हम obj2 के गुणों को बदलते हैं?

obj2.num = 1; 
obj2.str = 'baz'; 
obj2.obj.less = 'more'; 

console.log('[4] obj1:', obj1); 
console.log('[4] obj2:', obj2); 
for(var prop in obj1) console.log('[4] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop)); 
for(var prop in obj2) console.log('[4] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop)); 
"[4] obj1:" 
[object Object] { 
    num: 3, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "bar" 
} 
"[4] obj2:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "baz" 
} 
"[4] obj1.hasOwnProperty(num): true" 
"[4] obj1.hasOwnProperty(str): true" 
"[4] obj1.hasOwnProperty(obj): true" 
"[4] obj2.hasOwnProperty(num): true" 
"[4] obj2.hasOwnProperty(str): true" 
"[4] obj2.hasOwnProperty(obj): false" 

तो, num और strobj1 जैसे हम चाहते थे पर obj2 और नहीं पर बदल गया है, लेकिन obj1.obj.less बदल यह नहीं करना चाहिए था जब।

hasOwnProperty() चेक से हम इसे देख सकते हैं, भले ही हमने obj2.obj.less बदल दिया, हमने पहले obj2.obj सेट नहीं किया था। इसका मतलब है कि हम अभी भी obj1.obj.less का जिक्र कर रहे हैं।

चलिए obj1.obj से ऑब्जेक्ट बनाएं और इसे obj2.obj पर असाइन करें और देखें कि क्या हमें वह चीज़ मिलती है जिसे हम ढूंढ रहे हैं।

obj2.obj = Object.create(obj1.obj); 

console.log('[5] obj1:', obj1); 
console.log('[5] obj2:', obj2); 
for(var prop in obj1) console.log('[5] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop)); 
for(var prop in obj2) console.log('[5] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop)); 
"[5] obj1:" 
[object Object] { 
    num: 3, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "bar" 
} 
"[5] obj2:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "baz" 
} 
"[5] obj1.hasOwnProperty(num): true" 
"[5] obj1.hasOwnProperty(str): true" 
"[5] obj1.hasOwnProperty(obj): true" 
"[5] obj2.hasOwnProperty(num): true" 
"[5] obj2.hasOwnProperty(str): true" 
"[5] obj2.hasOwnProperty(obj): true" 

कि अच्छा है, अब obj2 अपनी ही obj संपत्ति है। चलो देखते हैं कि जब हम obj2.obj.less बदलते हैं तो क्या होता है।

obj2.obj.less = 'less'; 

console.log('[6] obj1:', obj1); 
console.log('[6] obj2:', obj2); 
"[6] obj1:" 
[object Object] { 
    num: 3, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "bar" 
} 
"[6] obj2:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "less" 
    }, 
    str: "baz" 
} 

तो क्या यह सब हमें बताता है कि, अगर संपत्ति अभी तक नहीं बनाया वस्तु पर नहीं बदला गया है, किसी भी get है कि संपत्ति के लिए बनाई गई वस्तु के लिए अनुरोध मूल वस्तु को भेजा जाएगा है।

पिछले कोड ब्लॉक से obj2.obj.less = 'more' के लिए set अनुरोध पहले obj2.obj के लिए एक get अनुरोध है, जो उस बिंदु पर obj2 में मौजूद नहीं है की आवश्यकता है, तो यह obj1.obj करने और बदले obj1.obj.less में अग्रेषित करता है।

फिर अंत में जब हम obj2 फिर से पढ़ें, हम अभी भी obj2.obj तो निर्धारित नहीं की है कि get अनुरोध obj1.obj को भेजा जाएगा और सेटिंग है कि हम पहले से बदल गया था लौटने के लिए, प्रभाव दूसरी वस्तुओं की एक संपत्ति को बदलने कि आपत्ति के कारण बच्चे दोनों को बदलना प्रतीत होता है, लेकिन वास्तव में यह वास्तव में केवल पहले ही बदल रहा है।


आप एक नया वस्तु पूरी तरह से रिकर्सिवली मूल से अलग वापस जाने के लिए इस सुविधा का उपयोग कर सकते हैं।

Demo

var obj1 = { 
    num : 1, 
    str : 'foo', 
    obj : { less: 'more' } 
}; 
var obj2 = separateObject(obj1); 

function separateObject(obj1) { 

    var obj2 = Object.create(Object.getPrototypeOf(obj1)); 
    for(var prop in obj1) { 
     if(typeof obj1[prop] === "object") 
      obj2[prop] = separateObject(obj1[prop]); 
     else 
      obj2[prop] = obj1[prop]; 
    } 

    return obj2; 
} 

console.log('[1] obj1:', obj1); 
console.log('[1] obj2:', obj2); 
for(var prop in obj1) console.log('[1] obj1.hasOwnProperty(' + prop + '): ' + obj1.hasOwnProperty(prop)); 
for(var prop in obj2) console.log('[1] obj2.hasOwnProperty(' + prop + '): ' + obj2.hasOwnProperty(prop)); 
"[1] obj1:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "foo" 
} 
"[1] obj2:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "foo" 
} 
"[1] obj1.hasOwnProperty(num): true" 
"[1] obj1.hasOwnProperty(str): true" 
"[1] obj1.hasOwnProperty(obj): true" 
"[1] obj2.hasOwnProperty(num): true" 
"[1] obj2.hasOwnProperty(str): true" 
"[1] obj2.hasOwnProperty(obj): true" 

देखते हैं क्या होता है जब हम अब कुछ चर बदल दें।

obj1.num = 3; 
obj1.str = 'bar'; 
obj1.obj.less = 'less'; 

console.log('[2] obj1:', obj1); 
console.log('[2] obj2:', obj2); 
"[2] obj1:" 
[object Object] { 
    num: 3, 
    obj: [object Object] { 
    less: "less" 
    }, 
    str: "bar" 
} 
"[2] obj2:" 
[object Object] { 
    num: 1, 
    obj: [object Object] { 
    less: "more" 
    }, 
    str: "foo" 
} 

सब कुछ सटीक रूप से आपकी जाने की उम्मीद काम करता है।

+0

विरासत संरचनाओं को दिखाए बिना, कंसोल.लॉग 'ऑब्जेक्ट्स क्या कंसोल करता है? – Bergi

+0

'differentObject' के लिए मैं' ऑब्जेक्ट.क्रेट (ऑब्जेक्ट.getPrototypeOf (obj1)) ' – Bergi

+0

' की सिफारिश करता हूं, मैंने जेएसबीन के कंसोल से आउटपुट की प्रतिलिपि बनाई। मैंने बस 'Object.getPrototypeOf (obj1)' की कोशिश की लेकिन यह एक खाली वस्तु लौटा दी। क्या मैं कुछ भूल रहा हूँ? मैं –

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