2011-05-27 16 views
9
Object.create = function (o) { 
    function F() {} 
    F.prototype = o; 
    return new F(); 
}; 

Prototypal Inheritance in JavaScriptजावास्क्रिप्ट में रिकर्सिव प्रोटोटाइप विरासत?

से मैं पिछले अभियानों से इनहेरिट नई वस्तुओं बनाने के लिए थोड़ी देर के लिए इस कोड का उपयोग किया गया है। हालांकि मैं थोड़ा आश्चर्यचकित हो गया।

a = { 
    foo: [1,2,3] 
} 

b = Object.create(a); 
// b.foo -> [1,2,3] 
b.foo = "test"; 
// b.foo -> "test" 
// a.foo -> [1,2,3] 

c = Object.create(a); 
// c.foo -> [1,2,3] 
c.foo[0] = 'test'; 
// c.foo -> ["test",2,3] 
// a.foo -> ["test",2,3] 

c.foo परिवर्तित करने का प्रयास में मैं a.foo बजाय बदल गया है, c.foo परिवर्तन दिखा है क्योंकि यह a से इनहेरिट है। एकमात्र समाधान मैं अभी देख ही b के प्रत्यक्ष गुण संशोधित करने के लिए है:

d = Object.create(a); 
d.foo = Object.create(a.foo); 
d.foo[0] = 'text'; 

मैं वहाँ एक बेहतर समाधान मैं याद कर रहा हूँ है यकीन है! मैं मूल वस्तुओं को संशोधित करने के जोखिम के बिना पुरानी वस्तुओं से नई वस्तुओं को कैसे बना सकता हूं?

उत्तर

1

+1 Crockford = डी

मुझे लगता है कि सरणियों हमेशा संदर्भ द्वारा पारित कर रहे हैं, और सरणी की नकल की कभी नहीं रही है संदर्भित करने के लिए। मुझे लगता है कि Array.slice इसे कॉपी करेगा, लेकिन यह एक फ्रिज केस है ...

निर्माण फ़ंक्शन का उपयोग ज्यादातर कार्यों और इस तरह की प्रतिलिपि बनाने के लिए किया जाता है। मैंने कभी, कि विधि का उपयोग नहीं के रूप में मैं सिर्फ एक निर्माता समारोह बना सकता हूँ:

function a() { 
    this.foo = [0, 1, 2]; 
} 

इस तरह, आप हमेशा प्रत्येक कॉल के लिए एक नई सरणी मिल जाएगा। बस बी = नया एक(); यह मेरे लिए काम करता है ...

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

+0

यह कहना है कि एक मूल्य "मूल्य/संदर्भ द्वारा पारित" है गलत है। मूल्य हमेशा जेएस में पारित किया जाता है। पैरामीटर्स ओटीओएच हमेशा "मूल्य से कॉल करें" का अर्थ है, जिसका तर्क है कि आप पैरामीटर सेट करते हैं, तर्क के बराबर होगा। पैरामीटर और तर्कों के बीच भी अंतर करें। पैरामीटर्स वास्तविक चर हैं, और तर्क मान हैं। 'फ़ंक्शन में (x) {} a (1) '' x' पैरामीटर है और '1' तर्क (/ मान) है। –

+0

उह ... मैंने या तो उल्लेख नहीं किया ... और Arrays विशेष वस्तुओं हैं। नोड से: var arr = [1, 2, 3]; > फ़ंक्शन कूल (टीएआरआर) {tArr.push (4);} > ठंडा (एआर); > arr; [1, 2, 3, 4] – tjameson

0

खैर हाँ:

1)

b.foo = "test"; 
// b.foo -> "test" 

"परीक्षण" के साथ एक के अपने F.prototype संदर्भ की जगह ताकि आप कोई त्रुटि देखते हैं, लेकिन वास्तव में यह है 2 बदतर तो)

2)

c = Object.create(a); 
// c.foo -> [1,2,3] 
c.foo[0] = 'test'; 
// c.foo -> ["test",2,3] 
// a.foo -> ["test",2,3] 

c.foo के बाद से एक वस्तु को संशोधित करता है [0] यह करने के लिए & a.foo बिंदु

समाधान here

+0

मैं इस प्रकार के कारण के लिए जावास्क्रिप्ट के साथ विरासत से बचने की कोशिश करता हूं। ऐसा कुछ कॉपी करने का कोई अच्छा तरीका नहीं है। क्या होगा, उदाहरण के लिए, सरणी सरणी की एक सरणी है, कई परतों को घोंसला घोंसला? इसका परिणाम धीमी वस्तु निर्माण में होता है। – tjameson

+0

तो आपको एक और गंभीर समाधान की आवश्यकता है: http://stackoverflow.com/questions/122102/what-is-the-most- कुशल-way-to-clone-a-javascript-object – selion

+0

बस विस्तृत विधि के माध्यम से पढ़ें। यह बहुत साफ है, लेकिन: https://github.com/documentcloud/underscore/issues/162#issuecomment-1014599 – tjameson

1

जब आप एक प्रोटोटाइप कोई नकल किया जाता है से एक नई वस्तु बनाने (वे एक मूल्य के लिए संदर्भ/संकेत दिए गए हैं)।यहां तक ​​कि नहीं संपत्ति की नकल की है:

function F() {} 
F.prototype.a = 1 
new F().hasOwnProperty("a") // => false 
new F().a // => 1 

आप

var f = new F(); 
f.a = 2; 

तो फिर तुम F.protoype में संपत्ति नहीं बदल रहे हैं, तो आप f के लिए एक नया प्रॉपर्टी जोड़ रहे हैं करते हैं:

var f = new F(); 
f.a = 2; 
f.a // => 2; 
delete f.a; 
f.a // => 1 

तो यह आपके द्वारा संपत्ति निर्दिष्ट करने वाले प्रत्येक मूल्य पर लागू होता है।

function F() { 
    this.a = []; 
} 
var f = new F(); 
var g = new F(); 
f.a === g.a // => false 

इस समस्या को केवल उठता है जब प्रोटोटाइप परिवर्तनशील मान हैं, अन्य मूल्यों नहीं किया जा सकता: यदि आप एक मूल्य के क्लोन करने के लिए चाहते हैं तो आप यह स्पष्ट रूप से क्या करना है, सबसे आसान तरीका सिर्फ निर्माता में एक नया गुण सेट करने के लिए है संशोधित (गुण इसके बजाय मूल्य बदल सकते हैं)।

और अगर आप "उपवर्ग" करना चाहते एफ, यह नया निर्माता से कॉल करने के लिए याद रखें:

function F() { this.a = []; } 
function G() { F.call(this); } 
G.prototype = new F(); 
0

यह वह जगह है समाधान:


Object.create = function (o) { 
    function F() { 
     for(var prop in this) 
      if(o.hasOwnProperty(prop)) 
       this[prop] = Object.create(o[prop]); 
    } 
    F.prototype = o; 
    return new F(); 
}; 

इस समाधान के जनरल प्रतिबंध यह है कि प्रोटोटाइप चाहिए है रिकर्सिव रेफरेंस नहीं है।

इसके अलावा इस समस्या को बिना किसी प्रतिबंध के हल करना संभव है, लेकिन समाधान अधिक जटिल होगा। अनंत रिकर्सिव ऑब्जेक्ट सृजन को रोकने के लिए आप प्रारंभिक प्रक्रिया के दौरान किसी प्रकार के अस्थायी मानचित्र संग्रहण का उपयोग कर सकते हैं। यह भंडारण आरंभिक वस्तुओं के बीच कैश संदर्भ होगा।

+0

यह काम नहीं प्रतीत होता है हालांकि मैं इसे आजमाता हूं! सबसे पहले एक अतिरिक्त ब्रैकेट के साथ एक टाइपो है और ओबीजे अनिर्धारित है। इसके अलावाऑनप्रोपर्टी हमेशा झूठी रहेगी क्योंकि 'इस' के निर्माण के दौरान केवल प्रोटोटाइप होगा। यदि आप इसके बजाय 'o' के गुणों को लूप करते हैं और इसे एफ में पास करते हैं तो यह वास्तव में अजीब परिणाम उत्पन्न करता है! – Annan

1

मैंने कभी देखा है कि सबसे अच्छा विरासत पैटर्न Google क्लोजर लाइब्रेरी है। यह रचनाकारों पर आधारित है। यहाँ उदाहरण है:

//with this method we will inherit one "class" (there are no real classes in JS) from another. 
var inherit = function (c, p) { 
    function F() {} 
    F.prototype = p.prototype; 
    c.prototype = new F; 
    c.prototype.constructor = c; 
}; 

//create one "class" 
var A = function(){ 
    this.foo = [1,2,3]; 
} 
//create its instance 
var a = new A(); 

//create another "class" 
var C = function(){ 
    //call the parent constructor 
    A.call(this); 
} 
//make inheritance 
inherit(C, A); 
//create example of inherited "class" 
var c = new C(); 

और परिणाम के रूप में आप चाहते हैं:

console.log(c.foo); 
//-> [1,2,3] 
c.foo[0] = 'test'; 
console.log(c.foo); 
//-> ['test',2,3] 
console.log(a.foo); 
//-> [1,2,3] 
संबंधित मुद्दे