के बीच क्या अंतर है
var A = function () {
this.x = function () {
//do something
};
};
तथा
var A = function () { };
A.prototype.x = function () {
//do something
};
a1.x !== a2.x
:; प्रोटोटाइप पर:a1.x === a2.x
के बीच क्या अंतर है
var A = function () {
this.x = function () {
//do something
};
};
तथा
var A = function () { };
A.prototype.x = function () {
//do something
};
a1.x !== a2.x
:; प्रोटोटाइप पर:a1.x === a2.x
जवाबों:
उदाहरणों के बहुत अलग परिणाम हैं।
मतभेदों को देखने से पहले, निम्नलिखित पर ध्यान दिया जाना चाहिए:
[[Prototype]]
संपत्ति के माध्यम से उदाहरणों के बीच तरीकों और मूल्यों को साझा करने का एक तरीका प्रदान करता है ।myObj.method()
) कहा जाता है, तो यह विधि के भीतर ऑब्जेक्ट को संदर्भित करता है। जहां यह कॉल द्वारा या बाइंड के उपयोग से सेट नहीं किया जाता है , यह वैश्विक ऑब्जेक्ट (किसी ब्राउज़र में विंडो) या सख्त मोड में चूक करता है, अपरिभाषित रहता है।तो यहाँ सवाल में स्निपेट हैं:
var A = function () {
this.x = function () {
//do something
};
};
इस स्थिति में, चर A
को एक मान दिया जाता है जो किसी फ़ंक्शन का संदर्भ होता है। कि समारोह का उपयोग कर कहा जाता है जब A()
, समारोह है इस कॉल से सेट नहीं है तो यह वैश्विक वस्तु को चूक और अभिव्यक्ति this.x
प्रभावी है window.x
। इसका परिणाम यह होता है कि दाएं हाथ की तरफ फ़ंक्शन एक्सप्रेशन का एक संदर्भ दिया जाता है window.x
।
के मामले में:
var A = function () { };
A.prototype.x = function () {
//do something
};
कुछ बहुत अलग होता है। पहली पंक्ति में, चर A
को एक फ़ंक्शन का संदर्भ दिया जाता है। जावास्क्रिप्ट में, सभी फ़ंक्शंस ऑब्जेक्ट में डिफ़ॉल्ट रूप से एक प्रोटोटाइप प्रॉपर्टी होती है, इसलिए A.prototype ऑब्जेक्ट बनाने के लिए कोई अलग कोड नहीं होता है ।
दूसरी पंक्ति में, A.prototyp.x को एक फ़ंक्शन का संदर्भ सौंपा गया है। यदि यह मौजूद नहीं है तो यह एक x गुण बना देगा , या यदि ऐसा होता है तो एक नया मान प्रदान करेगा। तो पहले उदाहरण के साथ अंतर जिसमें ऑब्जेक्ट की एक्स संपत्ति अभिव्यक्ति में शामिल है।
एक और उदाहरण नीचे है। यह पहले वाले के समान है (और शायद आपके कहने का मतलब क्या है):
var A = new function () {
this.x = function () {
//do something
};
};
इस उदाहरण में, new
ऑपरेटर को फ़ंक्शन अभिव्यक्ति से पहले जोड़ा गया है ताकि फ़ंक्शन को एक निर्माता के रूप में कहा जाए। जब बुलाया जाता है new
, तो फ़ंक्शन का यह एक नया ऑब्जेक्ट संदर्भित करने के लिए सेट होता है, जिसकी निजी [[Prototype]]
संपत्ति निर्माता के सार्वजनिक प्रोटोटाइप को संदर्भित करने के लिए सेट होती है । इसलिए असाइनमेंट स्टेटमेंट में, x
संपत्ति इस नई ऑब्जेक्ट पर बनाई जाएगी। जब एक निर्माता के रूप में कहा जाता है, तो एक फ़ंक्शन डिफ़ॉल्ट रूप से इस ऑब्जेक्ट को वापस करता है , इसलिए एक अलग return this;
बयान की आवश्यकता नहीं है ।
यह जाँचने के लिए कि A के पास x गुण है:
console.log(A.x) // function () {
// //do something
// };
इस की एक असामान्य इस्तेमाल होता है नए निर्माता को संदर्भित करने के लिए एक ही रास्ता के बाद से होकर जाता है A.constructor । यह करना अधिक सामान्य होगा:
var A = function () {
this.x = function () {
//do something
};
};
var a = new A();
एक समान परिणाम प्राप्त करने का दूसरा तरीका एक तुरंत लागू फ़ंक्शन अभिव्यक्ति का उपयोग करना है:
var A = (function () {
this.x = function () {
//do something
};
}());
इस मामले में, A
दाईं ओर फ़ंक्शन को कॉल करने का रिटर्न मान असाइन किया गया है। यहां फिर से, चूंकि यह कॉल में सेट नहीं है, यह वैश्विक ऑब्जेक्ट को संदर्भित करेगा और this.x
प्रभावी है window.x
। चूंकि फ़ंक्शन कुछ भी वापस नहीं करता है, A
का मान होगा undefined
।
दो दृष्टिकोणों के बीच ये अंतर यह भी प्रकट करते हैं कि आप JSON से / से अपनी जावास्क्रिप्ट ऑब्जेक्ट्स को क्रमबद्ध और डी-सीरियल कर रहे हैं या नहीं। जब आप ऑब्जेक्ट को क्रमबद्ध करते हैं, तो किसी ऑब्जेक्ट के प्रोटोटाइप पर परिभाषित तरीकों को क्रमबद्ध नहीं किया जाता है, जो तब सुविधाजनक हो सकता है जब आप किसी ऑब्जेक्ट के डेटा भागों को क्रमबद्ध करना चाहते हैं, लेकिन यह विधि नहीं है:
var A = function () {
this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance));
// {"objectsOwnProperties":"are serialized"}
संबंधित प्रश्न :
सिडेनोट: दो दृष्टिकोणों के बीच कोई महत्वपूर्ण मेमोरी सेविंग नहीं हो सकती है, हालांकि साझा करने के तरीकों और गुणों के प्रोटोटाइप का उपयोग करने से संभवतः प्रत्येक मेमोरी की तुलना में कम मेमोरी का उपयोग होगा।
जावास्क्रिप्ट एक निम्न-स्तरीय भाषा नहीं है। यह प्रोटोटाइप या अन्य वंशानुक्रम पैटर्न के बारे में सोचने के लिए बहुत मूल्यवान नहीं हो सकता है क्योंकि स्मृति को आवंटित करने के तरीके को स्पष्ट रूप से बदलना है।
null
) है, लेकिन यह prototype
संपत्ति से बहुत अलग है - जो कार्यों पर है और जिस पर सभी उदाहरणों का प्रोटोटाइप सेट किया गया है जब उनके साथ निर्माण किया जाता है new
। विश्वास नहीं कर सकता यह वास्तव में 87 अपवोट मिला :-(
"The language is functional"
क्या आप सुनिश्चित हैं कि यह क्या कार्यात्मक साधन है?
A
एक फ़ंक्शन के रूप में उपयोग करते हैं, और दूसरा आधा अस्पष्ट और अपरंपरागत तरीके से करना है सीधा कुछ।
जैसा कि अन्य लोगों ने कहा है कि "ए" के उपयोग से पहला संस्करण कक्षा ए के प्रत्येक उदाहरण में होता है, जिसमें फ़ंक्शन विधि "x" की अपनी स्वतंत्र प्रति होती है। जबकि "प्रोटोटाइप" का उपयोग करने का मतलब होगा कि कक्षा ए का प्रत्येक उदाहरण विधि "एक्स" की एक ही प्रति का उपयोग करेगा।
इस सूक्ष्म अंतर को दिखाने के लिए यहां कुछ कोड दिए गए हैं:
// x is a method assigned to the object using "this"
var A = function () {
this.x = function () { alert('A'); };
};
A.prototype.updateX = function( value ) {
this.x = function() { alert( value ); }
};
var a1 = new A();
var a2 = new A();
a1.x(); // Displays 'A'
a2.x(); // Also displays 'A'
a1.updateX('Z');
a1.x(); // Displays 'Z'
a2.x(); // Still displays 'A'
// Here x is a method assigned to the object using "prototype"
var B = function () { };
B.prototype.x = function () { alert('B'); };
B.prototype.updateX = function( value ) {
B.prototype.x = function() { alert( value ); }
}
var b1 = new B();
var b2 = new B();
b1.x(); // Displays 'B'
b2.x(); // Also displays 'B'
b1.updateX('Y');
b1.x(); // Displays 'Y'
b2.x(); // Also displays 'Y' because by using prototype we have changed it for all instances
जैसा कि दूसरों ने उल्लेख किया है, एक विधि या दूसरे को चुनने के विभिन्न कारण हैं। मेरा नमूना सिर्फ अंतर स्पष्ट रूप से प्रदर्शित करने के लिए है।
this
वस्तु पर कोई निर्भरता नहीं है , जो कि विधि का स्वामी है। अर्थात इस विधि का कोई ऐसा उद्देश्य नहीं है जो इसका स्वामी हो। इस मामले में एक this
ऑब्जेक्ट है, जैसा कि उदाहरण में कक्षा ए में दिखाया गया है।
ये 2 उदाहरण लें:
var A = function() { this.hey = function() { alert('from A') } };
बनाम
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
यहां ज्यादातर लोगों (विशेष रूप से शीर्ष-रेटेड उत्तर) ने यह बताने की कोशिश की कि वे WHY की व्याख्या किए बिना कैसे अलग हैं। मुझे लगता है कि यह गलत है और यदि आप बुनियादी बातों को पहले समझ लेते हैं, तो अंतर स्पष्ट हो जाएगा। आइए पहले बुनियादी बातों को समझाने की कोशिश करें ...
क) एक फ़ंक्शन जावास्क्रिप्ट में एक वस्तु है। जावास्क्रिप्ट में हर वस्तु को एक आंतरिक संपत्ति मिलती है (मतलब, आप इसे अन्य गुणों की तरह एक्सेस नहीं कर सकते हैं, शायद क्रोम जैसे ब्राउज़रों में छोड़कर), जिसे अक्सर संदर्भित किया जाता है __proto__
(आप वास्तव anyObject.__proto__
में इसे देखने के लिए क्रोम में टाइप कर सकते हैं। यह सिर्फ यही है। , एक संपत्ति, और कुछ नहीं। जावास्क्रिप्ट में एक संपत्ति = एक वस्तु के अंदर एक चर, और कुछ नहीं। चर क्या करते हैं? वे चीजों को इंगित करते हैं।
तो यह __proto__
संपत्ति किस ओर इशारा करती है? खैर, आमतौर पर एक और वस्तु (हम बाद में समझाएंगे)। __proto__
संपत्ति के लिए जावास्क्रिप्ट को बल देने का एकमात्र तरीका किसी अन्य वस्तु को इंगित नहीं करना है var newObj = Object.create(null)
। यहां तक कि अगर आप ऐसा करते हैं, तो __proto__
संपत्ति अभी भी ऑब्जेक्ट की संपत्ति के रूप में मौजूद है, बस यह किसी अन्य ऑब्जेक्ट को इंगित नहीं करता है, यह इंगित करता है null
।
यहाँ वह जगह है जहाँ ज्यादातर लोग भ्रमित होते हैं:
जब आप जावास्क्रिप्ट में एक नया फ़ंक्शन बनाते हैं (जो एक वस्तु के रूप में अच्छी तरह से याद है?), जिस क्षण इसे परिभाषित किया जाता है, जावास्क्रिप्ट स्वचालित रूप से उस फ़ंक्शन पर एक नई संपत्ति बनाता है जिसे कहा जाता है prototype
। कोशिश करो:
var A = [];
A.prototype // undefined
A = function() {}
A.prototype // {} // got created when function() {} was defined
A.prototype
__proto__
संपत्ति से पूरी तरह अलग है । हमारे उदाहरण में, 'A' में अब 'प्रोटोटाइप' नामक TWO गुण हैं और __proto__
। यह लोगों के लिए एक बड़ा भ्रम है। prototype
और __proto__
गुण किसी भी तरह से संबंधित नहीं हैं, वे अलग-अलग चीजें हैं जो अलग-अलग मूल्यों की ओर इशारा करते हैं।
आप आश्चर्यचकित हो सकते हैं: जावास्क्रिप्ट में __proto__
हर एक वस्तु पर संपत्ति क्यों बनाई गई है? खैर, एक शब्द: प्रतिनिधिमंडल । जब आप किसी ऑब्जेक्ट को किसी ऑब्जेक्ट पर कॉल करते हैं और ऑब्जेक्ट उसके पास नहीं होता है, तो जावास्क्रिप्ट ऑब्जेक्ट द्वारा संदर्भित ऑब्जेक्ट __proto__
को यह देखने के लिए देखता है कि क्या यह उसके पास है। यदि यह नहीं है, तो यह उस वस्तु की __proto__
संपत्ति और इसी तरह से दिखता है ... जब तक कि श्रृंखला समाप्त नहीं हो जाती। इस प्रकार नाम प्रोटोटाइप श्रृंखला । बेशक, यदि __proto__
कोई वस्तु इंगित नहीं करती है और इसके बजाय null
, अच्छी तरह से कठिन भाग्य को इंगित करती है , तो जावास्क्रिप्ट का एहसास होता है और आपको undefined
संपत्ति के लिए वापस कर देगा ।
आपको यह भी आश्चर्य हो सकता है कि prototype
जब आप फ़ंक्शन को परिभाषित करते हैं , तो जावास्क्रिप्ट एक फ़ंक्शन के लिए एक संपत्ति क्यों बनाता है ? क्योंकि यह आपको बेवकूफ बनाने की कोशिश करता है, हाँ आपको बेवकूफ बनाता है कि यह वर्ग-आधारित भाषाओं की तरह काम करता है।
चलो हमारे उदाहरण के साथ चलते हैं और एक "ऑब्जेक्ट" बनाते हैं A
:
var a1 = new A();
जब यह बात हुई तो पृष्ठभूमि में कुछ हो रहा है। a1
एक साधारण चर है जिसे एक नई, खाली वस्तु सौंपी गई थी।
तथ्य यह है कि new
एक फ़ंक्शन मंगलाचरण से पहले आपने ऑपरेटर का उपयोग किया A()
था, पृष्ठभूमि में कुछ ADDITIONAL किया। new
कीवर्ड एक नई वस्तु जो अब संदर्भ बनाया a1
और उस वस्तु खाली है। यहाँ इसके अतिरिक्त क्या हो रहा है:
हमने कहा कि प्रत्येक फ़ंक्शन परिभाषा पर बनाई गई एक नई प्रॉपर्टी prototype
(जिसे आप इसे एक्सेस कर सकते हैं, __proto__
संपत्ति के विपरीत ) बनाई गई है? खैर, उस संपत्ति का इस्तेमाल अब किया जा रहा है।
तो अब हम उस बिंदु पर हैं जहाँ हमारे पास एक ताज़ा बेक्ड खाली a1
वस्तु है। हमने कहा कि जावास्क्रिप्ट में सभी वस्तुओं में एक आंतरिक __proto__
गुण होता है जो किसी चीज़ की ओर इशारा करता है ( a1
यह भी है), चाहे वह शून्य हो या कोई अन्य वस्तु। new
ऑपरेटर क्या करता है यह उस __proto__
संपत्ति को फ़ंक्शन की prototype
संपत्ति को इंगित करने के लिए सेट करता है । उसे फिर से पढ़ें। यह मूल रूप से यह है:
a1.__proto__ = A.prototype;
हमने कहा कि A.prototype
एक खाली वस्तु से ज्यादा कुछ नहीं है (जब तक कि हम इसे परिभाषित करने से पहले किसी और चीज में नहीं बदलते a1
)। तो अब मूल रूप a1.__proto__
से उसी चीज़ की ओर A.prototype
इशारा करता है, जो कि खाली वस्तु है। वे दोनों उसी वस्तु की ओर संकेत करते हैं जो इस रेखा के बनने पर बनी थी:
A = function() {} // JS: cool. let's also create A.prototype pointing to empty {}
अब, जब var a1 = new A()
वक्तव्य संसाधित होता है तो एक और बात होती है। मूल रूप A()
से निष्पादित किया जाता है और यदि A कुछ इस तरह है:
var A = function() { this.hey = function() { alert('from A') } };
अंदर वह सब सामान function() { }
निष्पादित करने जा रहा है। जब आप this.hey..
लाइन पर पहुँचते हैं , तो this
इसे बदल दिया जाता है a1
और आपको यह मिल जाता है:
a1.hey = function() { alert('from A') }
मैं कवर नहीं करूंगा कि this
बदलाव क्यों होता है a1
लेकिन यह अधिक जानने के लिए एक शानदार उत्तर है।
इसलिए संक्षेप में, जब आप करते var a1 = new A()
हैं तो पृष्ठभूमि में 3 चीजें हो रही हैं:
a1
।a1 = {}
a1.__proto__
संपत्ति उसी बिंदु पर इंगित करने के लिए निर्दिष्ट की जाती A.prototype
है (दूसरी खाली वस्तु {})
फ़ंक्शन A()
को this
चरण 1 में बनाई गई नई, खाली ऑब्जेक्ट पर सेट के साथ निष्पादित किया जा रहा है (पढ़ें जवाब जो मैंने ऊपर संदर्भित किया है कि क्यों this
बदलता है a1
)
अब, चलो एक और वस्तु बनाने की कोशिश करते हैं:
var a2 = new A();
चरण 1,2,3 दोहराएंगे। क्या आप कुछ नोटिस? मुख्य शब्द रिपीट है। चरण 1: a2
एक नई खाली वस्तु होगी, चरण 2: इसकी __proto__
संपत्ति एक ही बात को इंगित करेगी A.prototype
और सबसे महत्वपूर्ण बात, चरण 3: फ़ंक्शन A()
फिर से निष्पादित होता है, जिसका अर्थ है कि एक फ़ंक्शन वाली संपत्ति a2
प्राप्त होगी hey
। a1
और a2
दो SEPARATE गुण हैं, hey
जो 2 SEPARATE फ़ंक्शन का नाम देते हैं! अब हमारे पास एक ही काम करने वाले दो अलग-अलग ऑब्जेक्ट्स में डुप्लिकेट फ़ंक्शन हैं, उफ़ ... आप इस के मेमोरी निहितार्थों की कल्पना कर सकते हैं यदि हमारे पास 1000 ऑब्जेक्ट्स बनाए गए हैं new A
, तो सभी फ़ंक्शंस घोषणाओं के बाद संख्या की तुलना में अधिक मेमोरी लेती हैं। 2. तो हम इसे कैसे रोकें?
याद रखें कि __proto__
प्रत्येक वस्तु पर संपत्ति क्यों मौजूद है? ताकि यदि आप उस yoMan
संपत्ति को पुनः प्राप्त करते हैं a1
(जो मौजूद नहीं है), तो उसकी __proto__
संपत्ति से परामर्श किया जाएगा, जो कि अगर यह एक वस्तु है (और यह सबसे अधिक मामले है), तो यह जांच करेगा कि क्या यह शामिल है yoMan
, और यदि यह नहीं है यह उस वस्तु के __proto__
आदि से परामर्श करेगा । यदि वह ऐसा करता है, तो वह उस संपत्ति का मूल्य लेगा और आपको प्रदर्शित करेगा।
तो किसी ने इस तथ्य + तथ्य का उपयोग करने का फैसला किया कि जब आप बनाते हैं a1
, तो इसकी __proto__
संपत्ति उसी (खाली) ऑब्जेक्ट को A.prototype
इंगित करती है और ऐसा करती है:
var A = function() {}
A.prototype.hey = function() { alert('from prototype') };
ठंडा! अब, जब आप बनाते हैं a1
, यह फिर से ऊपर के सभी 3 चरणों से गुजरता है, और चरण 3 में, यह कुछ भी नहीं करता है, क्योंकि function A()
निष्पादित करने के लिए कुछ भी नहीं है। और अगर हम करते हैं:
a1.hey
यह देखेगा कि a1
इसमें शामिल नहीं है hey
और यह देखने के लिए अपनी __proto__
संपत्ति वस्तु की जांच करेगा कि क्या यह है, जो कि मामला है।
इस दृष्टिकोण के साथ हम चरण 3 से उस हिस्से को समाप्त करते हैं जहां प्रत्येक नए ऑब्जेक्ट निर्माण पर कार्यों को दोहराया जाता है। इसके बजाय a1
और a2
एक अलग होने hey
संपत्ति, अब उनमें से कोई भी यह है। जो, मुझे लगता है, तुम अब तक अपने आप को पता लगा। यह अच्छी बात है ... यदि आप समझते हैं __proto__
और Function.prototype
, इन जैसे प्रश्न बहुत स्पष्ट होंगे।
नोट: कुछ लोग आंतरिक प्रोटोटाइप संपत्ति को कॉल नहीं करते हैं __proto__
, मैंने इस नाम को पोस्ट के माध्यम से Functional.prototype
दो अलग-अलग चीजों के रूप में संपत्ति में स्पष्ट रूप से अंतर करने के लिए उपयोग किया है।
__proto__
और .prototype
पूरी तरह से अलग चीजें हैं।
ज्यादातर मामलों में वे अनिवार्य रूप से समान होते हैं, लेकिन दूसरा संस्करण मेमोरी को बचाता है क्योंकि प्रत्येक ऑब्जेक्ट के लिए एक अलग फ़ंक्शन के बजाय फ़ंक्शन का केवल एक उदाहरण है।
पहले फॉर्म का उपयोग करने का एक कारण "निजी सदस्यों" का उपयोग करना है। उदाहरण के लिए:
var A = function () {
var private_var = ...;
this.x = function () {
return private_var;
};
this.setX = function (new_x) {
private_var = new_x;
};
};
जावास्क्रिप्ट के डांटने के नियमों के कारण, Private_var इस .x को दिए गए फ़ंक्शन के लिए उपलब्ध है, लेकिन ऑब्जेक्ट के बाहर नहीं।
पहला उदाहरण केवल उस ऑब्जेक्ट के लिए इंटरफ़ेस बदलता है। दूसरा उदाहरण उस वर्ग के सभी ऑब्जेक्ट के लिए इंटरफ़ेस को बदलता है।
x
को उन सभी वस्तुओं के लिए उपलब्ध कराएंगे, जिनके प्रोटोटाइप को A का एक नया उदाहरण सौंपा गया है:function B () {}; B.prototype = new A(); var b = new B(); b.x() // Will call A.x if A is defined by first example;
इसके this
बजाय का उपयोग करने के साथ अंतिम समस्या prototype
यह है कि एक विधि को ओवरराइड करते समय, बेस क्लास का निर्माता अभी भी ओवरराइड विधि का उल्लेख करेगा। इस पर विचार करो:
BaseClass = function() {
var text = null;
this.setText = function(value) {
text = value + " BaseClass!";
};
this.getText = function() {
return text;
};
this.setText("Hello"); // This always calls BaseClass.setText()
};
SubClass = function() {
// setText is not overridden yet,
// so the constructor calls the superclass' method
BaseClass.call(this);
// Keeping a reference to the superclass' method
var super_setText = this.setText;
// Overriding
this.setText = function(value) {
super_setText.call(this, "SubClass says: " + value);
};
};
SubClass.prototype = new BaseClass();
var subClass = new SubClass();
console.log(subClass.getText()); // Hello BaseClass!
subClass.setText("Hello"); // setText is already overridden
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
बनाम:
BaseClass = function() {
this.setText("Hello"); // This calls the overridden method
};
BaseClass.prototype.setText = function(value) {
this.text = value + " BaseClass!";
};
BaseClass.prototype.getText = function() {
return this.text;
};
SubClass = function() {
// setText is already overridden, so this works as expected
BaseClass.call(this);
};
SubClass.prototype = new BaseClass();
SubClass.prototype.setText = function(value) {
BaseClass.prototype.setText.call(this, "SubClass says: " + value);
};
var subClass = new SubClass();
console.log(subClass.getText()); // SubClass says: Hello BaseClass!
अगर आपको लगता है कि यह कोई समस्या नहीं है, तो यह इस बात पर निर्भर करता है कि क्या आप निजी चर के बिना रह सकते हैं, और क्या आप एक लीक को देखने के लिए पर्याप्त अनुभवी हैं या नहीं। इसके अलावा, विधि की परिभाषा के बाद निर्माण तर्क को रखना असुविधाजनक है।
var A = function (param1) {
var privateVar = null; // Private variable
// Calling this.setPrivateVar(param1) here would be an error
this.setPrivateVar = function (value) {
privateVar = value;
console.log("setPrivateVar value set to: " + value);
// param1 is still here, possible memory leak
console.log("setPrivateVar has param1: " + param1);
};
// The constructor logic starts here possibly after
// many lines of code that define methods
this.setPrivateVar(param1); // This is valid
};
var a = new A(0);
// setPrivateVar value set to: 0
// setPrivateVar has param1: 0
a.setPrivateVar(1);
//setPrivateVar value set to: 1
//setPrivateVar has param1: 0
बनाम:
var A = function (param1) {
this.setPublicVar(param1); // This is valid
};
A.prototype.setPublicVar = function (value) {
this.publicVar = value; // No private variable
};
var a = new A(0);
a.setPublicVar(1);
console.log(a.publicVar); // 1
प्रत्येक वस्तु एक प्रोटोटाइप वस्तु से जुड़ी होती है। जब मौजूद संपत्ति का उपयोग करने की कोशिश नहीं की जाती है, तो जावास्क्रिप्ट उस संपत्ति के लिए ऑब्जेक्ट के प्रोटोटाइप ऑब्जेक्ट को देखेगा और मौजूद होने पर उसे वापस कर देगा।
prototype
एक फ़ंक्शन कंस्ट्रक्टर की संपत्ति का उपयोग करते समय उस फ़ंक्शन के साथ बनाए गए सभी उदाहरणों के प्रोटोटाइप ऑब्जेक्ट को संदर्भित करता है new
।
अपने पहले उदाहरण में, आप फ़ंक्शन x
के साथ बनाए गए प्रत्येक उदाहरण में एक संपत्ति जोड़ रहे हैं A
।
var A = function () {
this.x = function () {
//do something
};
};
var a = new A(); // constructor function gets executed
// newly created object gets an 'x' property
// which is a function
a.x(); // and can be called like this
दूसरे उदाहरण में आप प्रोटोटाइप ऑब्जेक्ट में एक संपत्ति जोड़ रहे हैं जो A
बिंदु के साथ बनाए गए सभी उदाहरण हैं ।
var A = function () { };
A.prototype.x = function () {
//do something
};
var a = new A(); // constructor function gets executed
// which does nothing in this example
a.x(); // you are trying to access the 'x' property of an instance of 'A'
// which does not exist
// so JavaScript looks for that property in the prototype object
// that was defined using the 'prototype' property of the constructor
अंत में, पहले उदाहरण में फ़ंक्शन की एक प्रति प्रत्येक उदाहरण को सौंपी जाती है । दूसरे उदाहरण में फ़ंक्शन की एक एकल प्रतिलिपि सभी उदाहरणों द्वारा साझा की जाती है ।
क्या फर्क पड़ता है? => बहुत कुछ।
मुझे लगता है, this
एन्कैप्सुलेशन को सक्षम करने के लिए संस्करण का उपयोग किया जाता है, अर्थात डेटा छिपाना। यह निजी चरों में हेरफेर करने में मदद करता है।
आइए हम निम्नलिखित उदाहरण देखें:
var AdultPerson = function() {
var age;
this.setAge = function(val) {
// some housekeeping
age = val >= 18 && val;
};
this.getAge = function() {
return age;
};
this.isValid = function() {
return !!age;
};
};
अब, prototype
संरचना को निम्नलिखित के रूप में लागू किया जा सकता है:
अलग-अलग वयस्कों की अलग-अलग उम्र होती है, लेकिन सभी वयस्कों को समान अधिकार मिलते हैं।
इसलिए, हम इसे इसके बजाय प्रोटोटाइप का उपयोग करके जोड़ते हैं।
AdultPerson.prototype.getRights = function() {
// Should be valid
return this.isValid() && ['Booze', 'Drive'];
};
अब कार्यान्वयन को देखते हैं।
var p1 = new AdultPerson;
p1.setAge(12); // ( age = false )
console.log(p1.getRights()); // false ( Kid alert! )
p1.setAge(19); // ( age = 19 )
console.log(p1.getRights()); // ['Booze', 'Drive'] ( Welcome AdultPerson )
var p2 = new AdultPerson;
p2.setAge(45);
console.log(p2.getRights()); // The same getRights() method, *** not a new copy of it ***
उम्मीद है की यह मदद करेगा।
प्रोटोटाइप कक्षा का टेम्पलेट है; जो भविष्य के सभी उदाहरणों पर लागू होता है। जबकि यह वस्तु का विशेष उदाहरण है।
मुझे पता है कि यह मौत के लिए उत्तर दिया गया है, लेकिन मैं गति के अंतर का वास्तविक उदाहरण दिखाना चाहूंगा।
यहां हम print
क्रोम में एक विधि के साथ 2,000,000 नई वस्तुओं का निर्माण कर रहे हैं । हम प्रत्येक ऑब्जेक्ट को एक सरणी में संग्रहीत कर रहे हैं। print
प्रोटोटाइप पर डालने में लगभग 1/2 समय लगता है।
मैं आपको एक अधिक व्यापक उत्तर देता हूं जो मैंने जावास्क्रिप्ट प्रशिक्षण पाठ्यक्रम के दौरान सीखा था।
अधिकांश उत्तरों में पहले से ही अंतर का उल्लेख है, अर्थात जब फ़ंक्शन को प्रोटोटाइप करना सभी (भविष्य) उदाहरणों के साथ साझा किया जाता है। जबकि कक्षा में फ़ंक्शन की घोषणा करने से प्रत्येक उदाहरण के लिए एक प्रतिलिपि बनाई जाएगी।
सामान्य तौर पर कोई सही या गलत नहीं है, यह आपकी आवश्यकताओं के आधार पर अधिक स्वाद या डिजाइन निर्णय का मामला है। हालांकि प्रोटोटाइप एक ऐसी तकनीक है जिसका उपयोग ऑब्जेक्ट ओरिएंटेड तरीके से विकसित करने के लिए किया जाता है, जैसा कि मुझे आशा है कि आप इस उत्तर के अंत में देखेंगे।
आपने अपने प्रश्न में दो पैटर्न दिखाए। मैं दो और समझाने की कोशिश करूंगा और अगर प्रासंगिक हो तो मतभेदों को समझाने की कोशिश करूंगा। बेझिझक संपादित करें / विस्तारित करें। सभी उदाहरणों में यह एक कार ऑब्जेक्ट के बारे में है जिसमें एक स्थान है और वह स्थानांतरित कर सकता है।
यकीन नहीं होता कि यह पैटर्न आजकल भी प्रासंगिक है, लेकिन यह मौजूद है। और इसके बारे में जानना अच्छा है। आप बस डेकोरेटर फ़ंक्शन में ऑब्जेक्ट और प्रॉपर्टी पास करते हैं। डेकोरेटर संपत्ति और विधि के साथ वस्तु वापस करता है।
var carlike = function(obj, loc) {
obj.loc = loc;
obj.move = function() {
obj.loc++;
};
return obj;
};
var amy = carlike({}, 1);
amy.move();
var ben = carlike({}, 9);
ben.move();
जावास्क्रिप्ट में एक समारोह एक विशेष वस्तु है। आह्वान किए जाने के अलावा, एक फ़ंक्शन किसी अन्य ऑब्जेक्ट की तरह गुणों को संग्रहीत कर सकता है।
इस मामले Car
में एक फ़ंक्शन ( यह भी लगता है कि वस्तु ) है कि आप के रूप में इस्तेमाल किया जा सकता है। इसमें एक संपत्ति है methods
(जो कि एक move
फ़ंक्शन के साथ एक ऑब्जेक्ट है )। जब Car
आह्वान किया जाता है तो extend
फ़ंक्शन को कहा जाता है, जो कुछ जादू करता है, और Car
फ़ंक्शन (थिंक ऑब्जेक्ट) को विस्तारित तरीकों के भीतर विस्तारित करता है methods
।
यह उदाहरण, हालांकि अलग है, सवाल में पहले उदाहरण के सबसे करीब आता है।
var Car = function(loc) {
var obj = {loc: loc};
extend(obj, Car.methods);
return obj;
};
Car.methods = {
move : function() {
this.loc++;
}
};
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
पहले दो पैटर्न साझा तरीकों को परिभाषित करने या निर्माणकर्ता के शरीर में इनलाइन परिभाषित तरीकों का उपयोग करने की तकनीक का उपयोग करने की चर्चा करते हैं। दोनों मामलों में हर उदाहरण का अपना move
कार्य है।
प्रोटोटाइप पैटर्न खुद को एक ही परीक्षा में अच्छी तरह से उधार नहीं देता है, क्योंकि प्रोटोटाइप प्रतिनिधिमंडल के माध्यम से फ़ंक्शन साझा करना प्रोटोटाइप पैटर्न के लिए बहुत ही लक्ष्य है। जैसा कि अन्य ने बताया है, यह एक बेहतर स्मृति पदचिह्न होने की उम्मीद है।
हालांकि यह जानना एक दिलचस्प बात है कि: प्रत्येक prototype
वस्तु के पास एक सुविधा संपत्ति होती है constructor
, जो फ़ंक्शन (थिंक ऑब्जेक्ट) पर वापस लौटती है।
अंतिम तीन पंक्तियों के बारे में:
इस उदाहरण में Car
करने के लिए लिंक prototype
वस्तु है, जो के माध्यम से लिंक constructor
करने के लिए Car
ही है, यानी Car.prototype.constructor
है Car
ही। यह आपको यह पता लगाने की अनुमति देता है कि किस निर्माता फ़ंक्शन ने एक निश्चित ऑब्जेक्ट बनाया है।
amy.constructor
लुकअप विफल हो जाता है और इस प्रकार उसे सौंप दिया जाता है Car.prototype
, जिसमें कंस्ट्रक्टर की संपत्ति होती है। और ऐसा amy.constructor
है Car
।
इसके अलावा, amy
एक है instanceof
Car
। instanceof
ऑपरेटर यह देखकर काम करता है कि क्या दाहिने ऑपरेटर की प्रोटोटाइप ऑब्जेक्ट ( Car
) बाएं ऑपरेटर के प्रोटोटाइप ( amy
) श्रृंखला में कहीं भी पाई जा सकती है ।
var Car = function(loc) {
var obj = Object.create(Car.prototype);
obj.loc = loc;
return obj;
};
Car.prototype.move = function() {
this.loc++;
};
var amy = Car(1);
amy.move();
var ben = Car(9);
ben.move();
console.log(Car.prototype.constructor);
console.log(amy.constructor);
console.log(amy instanceof Car);
कुछ डेवलपर्स शुरुआत में भ्रमित हो सकते हैं। नीचे दिए गए उदाहरण देखें:
var Dog = function() {
return {legs: 4, bark: alert};
};
var fido = Dog();
console.log(fido instanceof Dog);
instanceof
ऑपरेटर रिटर्न false
, क्योंकि Dog
के प्रोटोटाइप में कहीं भी नहीं पाया जा सकता fido
रों प्रोटोटाइप श्रृंखला '। fido
एक साधारण वस्तु है जो एक वस्तु शाब्दिक के साथ बनाई गई है, अर्थात यह केवल प्रतिनिधि है Object.prototype
।
यह वास्तव में सरलीकृत रूप में प्रोटोटाइप पैटर्न का सिर्फ एक और रूप है और उदाहरण के लिए जावा में प्रोग्राम करने वालों के लिए अधिक परिचित है, क्योंकि यह new
कंस्ट्रक्टर का उपयोग करता है ।
यह वास्तव में प्रोटोटाइप पैटर्न के रूप में ही करता है, यह सिर्फ प्रोटोटाइप पैटर्न के सिंटैक्टिक शुगर ओवरटॉप है।
हालांकि, प्राथमिक अंतर यह है कि जावास्क्रिप्ट इंजनों में कार्यान्वित अनुकूलन हैं जो केवल छद्मशास्त्रीय पैटर्न का उपयोग करते समय लागू होते हैं। छद्मशास्त्रीय पैटर्न के बारे में सोचें जो प्रोटोटाइप पैटर्न का संभवतः तेज़ संस्करण है; दोनों उदाहरणों में वस्तु संबंध समान हैं।
var Car = function(loc) {
this.loc = loc;
};
Car.prototype.move = function() {
this.loc++;
};
var amy = new Car(1);
amy.move();
var ben = new Car(9);
ben.move();
अंत में, यह महसूस करना बहुत मुश्किल नहीं होना चाहिए कि ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग कैसे की जा सकती है। दो खंड हैं।
एक खंड जो प्रोटोटाइप (श्रृंखला) में सामान्य गुणों / विधियों को परिभाषित करता है।
और एक अन्य खंड जहां आप परिभाषाओं को एक दूसरे से अलग करते हैं ( loc
उदाहरणों में चर)।
यह वही है जो हमें जावास्क्रिप्ट में सुपरक्लास या उपवर्ग जैसी अवधारणाओं को लागू करने की अनुमति देता है।
जोड़ने या संपादित करने के लिए स्वतंत्र महसूस करें। एक बार और पूरा होने पर मैं इसे सामुदायिक विकि बना सकता हूँ।
मेरा मानना है कि @ मट्टू क्रुमले सही हैं। वे कार्यात्मक रूप से , यदि संरचनात्मक रूप से, समतुल्य नहीं हैं। यदि आप फायरबग का उपयोग उन वस्तुओं को देखने के लिए करते हैं जो उपयोग करके बनाई गई हैं new
, तो आप देख सकते हैं कि वे समान हैं। हालाँकि, मेरी प्राथमिकता निम्नलिखित होगी। मैं यह अनुमान लगा रहा हूं कि यह सिर्फ C # / Java में मेरे द्वारा उपयोग की जाने वाली चीज़ों के समान है। यही है, वर्ग को परिभाषित करें, फ़ील्ड, कंस्ट्रक्टर और विधियों को परिभाषित करें।
var A = function() {};
A.prototype = {
_instance_var: 0,
initialize: function(v) { this._instance_var = v; },
x: function() { alert(this._instance_var); }
};
EDIT का मतलब यह नहीं था कि चर का दायरा निजी था, मैं सिर्फ यह बताने की कोशिश कर रहा था कि मैं अपनी कक्षाओं को जावास्क्रिप्ट में कैसे परिभाषित करता हूं। इसे दर्शाने के लिए परिवर्तनशील नाम को बदल दिया गया है।
initialize
और x methods do not refer to the
_instance_var` संपत्ति के रूप में A
, लेकिन एक वैश्विक एक के लिए। this._instance_var
यदि आप उदाहरण की _instance_var
संपत्ति का उपयोग करना चाहते हैं, तो उपयोग करें A
।
जैसा कि अन्य उत्तरों में चर्चा की गई है, यह वास्तव में एक प्रदर्शन विचार है क्योंकि प्रोटोटाइप में फ़ंक्शन को सभी तात्कालिकता के साथ साझा किया जाता है - बजाय प्रत्येक तात्कालिकता के लिए बनाए जा रहे फ़ंक्शन के बजाय।
मैंने यह दिखाने के लिए एक jsperf को एक साथ रखा। कक्षा को तुरंत करने में लगने वाले समय में एक नाटकीय अंतर है, हालांकि यह वास्तव में केवल प्रासंगिक है यदि आप कई उदाहरण बना रहे हैं।