2012-11-16 26 views
27

सी ++ में, भाषा के साथ मैं सबसे अधिक आरामदायक हूँ, आम तौर पर एक इस तरह एक वस्तु वाणी:जावास्क्रिप्ट: क्या मुझे किसी ऑब्जेक्ट में प्रत्येक चर के लिए यह.var डालना होगा?

class foo 
{ 
public: 
    int bar; 
    int getBar() { return bar; } 
} 

कॉलिंग getBar() ठीक काम करता है (तथ्य यह है कि bar अप्रारंभीकृत किया जा सकता है अनदेखी)। bargetBar() कक्षा foo के दायरे में है, इसलिए मुझे this->bar कहने की आवश्यकता नहीं है जब तक कि मुझे वास्तव में यह स्पष्ट करने की आवश्यकता न हो कि मैं कक्षा के bar के बजाय पैरामीटर कहता हूं।

अब, मैं जावास्क्रिप्ट में ओओपी के साथ शुरू करने की कोशिश कर रहा हूं। तो, मैं ऊपर देखो कैसे वर्गों को परिभाषित और बात का एक ही तरह की कोशिश करने के लिए:

function foo() 
{ 
    this.bar = 0; 
    this.getBar = function() { return bar; } 
} 

और यह मुझे bar is undefined देता है। bar से this.bar को बदलना समस्या को हल करता है, लेकिन यह मेरे कोड को हर चरम क्लटर के लिए कर रहा है। क्या यह हर चर के लिए आवश्यक है? चूंकि मुझे इससे संबंधित कोई प्रश्न नहीं मिल रहा है, इसलिए मुझे ऐसा लगता है कि मैं कुछ मौलिक रूप से गलत कर रहा हूं।


संपादित करें: ठीक है, तो, टिप्पणी है कि मैं क्या हो रही है से कि this.bar, किसी वस्तु की संपत्ति, bar से संदर्भ के लिए कुछ अलग, एक स्थानीय चर रहा है। क्या कोई कह सकता है कि यह वास्तव में क्यों है, स्कोपिंग और ऑब्जेक्ट्स के मामले में, और यदि किसी ऑब्जेक्ट को परिभाषित करने का कोई और तरीका है जहां यह आवश्यक नहीं है?

+2

है 'एक वस्तु संपत्ति .bar' है, एक चर नहीं। तो हाँ, किसी ऑब्जेक्ट से संपत्ति प्राप्त करने के लिए, आपको उस ऑब्जेक्ट के कुछ संदर्भों के माध्यम से ऐसा करने की आवश्यकता है। यदि 'यह 'आपकी वस्तु का संदर्भ देता है, तो' this.bar' आपको वह संपत्ति देगा। –

+3

'this.bar'' bar' जैसा नहीं है। हालांकि आप 'var bar = this.bar' कर सकते हैं जो 'bar' संदर्भ' this.bar' – Loktar

+0

@Loktar बना देगा, लेकिन केवल तभी होगा जब यह'bar.bar' ऑब्जेक्ट या सरणी है ... – Alnitak

उत्तर

31

जावास्क्रिप्ट में कक्षा कक्षा-आधारित ऑब्जेक्ट मॉडल नहीं है। यह शक्तिशाली प्रोटोटाइपिकल विरासत का उपयोग करता है, जो कक्षाओं की नकल कर सकता है, लेकिन इसके लिए उपयुक्त नहीं है। सबकुछ एक वस्तु है, और वस्तुएं अन्य वस्तुओं से प्राप्त हो सकती हैं।

एक कन्स्ट्रक्टर केवल एक ऐसा कार्य है जो नव निर्मित वस्तुओं को गुण निर्दिष्ट करता है। ऑब्जेक्ट (new keyword के साथ कॉल द्वारा बनाया गया) this keyword (जो फ़ंक्शन के लिए स्थानीय है) को संदर्भित किया जा सकता है।

एक विधि भी एक कार्य है जिसे पर एक ऑब्जेक्ट कहा जाता है - फिर ऑब्जेक्ट को इंगित करने के लिए this के साथ। कम से कम जब उस कार्य को member operator (डॉट, ब्रैकेट) का उपयोग करके ऑब्जेक्ट की संपत्ति के रूप में बुलाया जाता है। इससे नए लोगों के लिए बहुत भ्रम पैदा होता है, क्योंकि यदि आप उस फ़ंक्शन के आसपास गुजरते हैं (उदा। एक ईवेंट श्रोता के लिए) यह उस ऑब्जेक्ट से "अलग" होता है जिस पर इसे एक्सेस किया गया था।

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

उदाहरण:

function Foo() { 
    this.bar = "foo"; // creating a property on the instance 
} 
Foo.prototype.foo = 0; // of course you also can define other values to inherit 
Foo.prototype.getBar = function() { 
    // quite useless 
    return this.bar; 
} 

var foo = new Foo; // creates an object which inherits from Foo.prototype, 
        // applies the Foo constructor on it and assigns it to the var 
foo.getBar(); // "foo" - the inherited function is applied on the object and 
       // returns its "bar" property 
foo.bar; // "foo" - we could have done this easier. 
foo[foo.bar]; // 0 - access the "foo" property, which is inherited 
foo.foo = 1; // and now overwrite it by creating an own property of foo 
foo[foo.getBar()]; // 1 - gets the overwritten property value. Notice that 
(new Foo).foo;  // is still 0 

तो, हम केवल उस वस्तु के गुणों का उपयोग करें और इसके साथ खुश हैं किया था। लेकिन वे सभी "सार्वजनिक" हैं, और ओवरराइट/बदला/हटाया जा सकता है! यदि इससे कोई फर्क नहीं पड़ता, तो आप भाग्यशाली हैं। आप अंडरस्कोर के साथ अपने नामों का उपसर्ग करके गुणों की "निजीता" को इंगित कर सकते हैं, लेकिन यह केवल अन्य डेवलपर्स के लिए एक संकेत है और इसका पालन नहीं किया जा सकता है (विशेष रूप से त्रुटि में)।

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

चलो यह कार्रवाई में देखें:

function Foo() { 
    var bar = "foo"; // a local variable 
    this.getBar = function getter() { 
     return bar; // accesses the local variable 
    }; // the assignment to a property makes it available to outside 
} 

var foo = new Foo; // an object with one method, inheriting from a [currently] empty prototype 
foo.getBar(); // "foo" - receives us the value of the "bar" variable in the constructor 

यह गेटर समारोह है, जो निर्माता के अंदर परिभाषित किया गया है, अब एक "विशेषाधिकार प्राप्त विधि" यह "निजी" के लिए उपयोग (स्थानीय) के रूप में कहा जाता है "गुण" (चर)। bar का मान कभी नहीं बदलेगा। आप इसके लिए एक सेटर फ़ंक्शन भी घोषित कर सकते हैं, और इसके साथ आप कुछ सत्यापन आदि जोड़ सकते हैं।

ध्यान दें कि प्रोटोटाइप ऑब्जेक्ट पर विधियों को कन्स्ट्रक्टर के स्थानीय चर तक पहुंच नहीं है, फिर भी वे शायद विशेषाधिकार प्राप्त विधियों का उपयोग करें। आइए एक जोड़ें:

Foo.prototype.getFooBar = function() { 
    return this.getBar() + "bar"; // access the "getBar" function on "this" instance 
} 
// the inheritance is dynamic, so we can use it on our existing foo object 
foo.getFooBar(); // "foobar" - concatenated the "bar" value with a custom suffix 

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

जब आप एक "कक्षा" से दूसरे में विरासत स्थापित कर रहे होते हैं तो यह थोड़ा और जटिल हो जाता है - मूल रूप से आपको बच्चे के प्रोटोटाइप ऑब्जेक्ट को माता-पिता से प्राप्त करना होता है, और बच्चे के उदाहरणों पर मूल निर्माता को लागू करना होता है "निजी गुण"। Correct javascript inheritance, Private variables in inherited prototypes, Define Private field Members and Inheritance in JAVASCRIPT module pattern और How to implement inheritance in JS Revealing prototype pattern?

+0

यह मेरी समझ के साथ बहुत कुछ करने में मदद करता है यहाँ जा रहा है असल में, मूल प्रेरक सिर्फ मुझे यह सब कुछ के सामने रखने के लिए नाराज था, लेकिन वास्तव में समझ में आया कि मुझे अच्छा क्यों होना है। – Chaosed0

+0

ईसीएमएस्क्रिप्ट में कोई "सदस्य ऑपरेटर" नहीं है। उचित शब्द "[संपत्ति एक्सेसर] है (http: // ecma-international।संगठन/ecma-262/5.1/# sec-11.2.1) नोटेशन "। – PointedEars

+0

@PointedEars: निश्चित रूप से, यह आधिकारिक शब्द है। लेकिन क्या "सदस्य ऑपरेटर" (एमडीएन द्वारा प्रतीत होता है) वास्तव में गलत या गैर-वर्णनात्मक है? निश्चित रूप से गणितीय भावना में ऑपरेटर, बाइनरी ईएस ऑपरेटर (§11.5-11.11) – Bergi

2

पर एक नजर है जावास्क्रिप्ट में OOP के करीब पाने के लिए आपको एक मॉड्यूल डिजाइन पैटर्न में देखने के लिए चाहते हो सकता है (उदाहरण के लिए, here बताया गया है)।

बंद होने के प्रभाव के आधार पर, यह पैटर्न आपकी वस्तुओं में निजी गुणों को अनुकरण करने की अनुमति देता है।

'निजी' गुणों के साथ आप सीधे उनके पहचानकर्ता द्वारा संदर्भित कर सकते हैं (यानी, this कीवर्ड कन्स्ट्रक्टर के रूप में)।

लेकिन जेएस में किसी भी तरह, बंद और डिज़ाइन पैटर्न - एक उन्नत विषय। तो, मूल बातें से परिचित हो जाएं (पहले बताई गई पुस्तक में भी समझाया गया है)।

+0

वापस जाकर इस आलेख को देखकर (यह निश्चित रूप से एक पुस्तक होने की लंबाई है, लेकिन यह प्रकाशित नहीं होता प्रतीत होता है) बहुत उपयोगी है। इसे मेरी आंखों के नीचे लाने के लिए धन्यवाद। – Chaosed0

+0

@ Chaosed0 हमेशा स्वागत है! जेएस में डिजाइन पैटर्न पर कई किताबें/लेख पढ़ने योग्य नहीं हैं, लेकिन यह एक अच्छा है। –

2

जावास्क्रिप्ट में this हमेशा फ़ंक्शन के स्वामी ऑब्जेक्ट को संदर्भित करता है। उदाहरण के लिए, यदि आप किसी पृष्ठ में अपने फ़ंक्शन foo() को परिभाषित करते हैं, तो स्वामी जावास्क्रिप्ट ऑब्जेक्ट windows है; या यदि आप foo() को HTML तत्व <body> पर परिभाषित करते हैं, तो स्वामी HTML तत्व निकाय है; और इसी तरह यदि आप तत्व <a> पर फ़ंक्शन पर क्लिक करते हैं, तो मालिक एंकर है।

अपने मामले में, आप शुरुआत में 'मालिक' ऑब्जेक्ट में bar संपत्ति को स्थानीय चर bar वापस करने का प्रयास कर रहे हैं।

चूंकि आपने कभी भी स्थानीय वैरिएल्बे bar परिभाषित नहीं किया है, यह आपको बार के रूप में अनिर्धारित कर रहा है।

आदर्श रूप से आपके कोड को वैरिएबल को var bar; के रूप में परिभाषित किया जाना चाहिए यदि आप मान शून्य वापस करना चाहते हैं।

6

स्पष्ट रूप से कह रहा है कि this.foo का अर्थ है (जैसा कि आप अच्छी तरह से समझ गए हैं) कि this द्वारा संदर्भित वर्तमान ऑब्जेक्ट की foo संपत्ति के बारे में आप रुचि रखते हैं। तो यदि आप इसका उपयोग करते हैं: this.foo = 'bar'; आप this द्वारा संदर्भित वर्तमान ऑब्जेक्ट की foo को bar के बराबर सेट करने जा रहे हैं।

this जावास्क्रिप्ट में कीवर्ड हमेशा सी ++ में समान चीज़ का मतलब नहीं है। ऊपर हम समारोह Developer तो this वस्तु जो Developer द्वारा बनाया जाएगा करने के लिए संदर्भित कर रहा है के संदर्भ के साथ समारोह Person कॉल कर रहे हैं

function Person(name) { 
    this.name = name; 
    console.log(this); //Developer {language: "js", name: "foo"} if called by Developer 
} 

function Developer(name, language) { 
    this.language = language; 
    Person.call(this, name); 
} 

var dev = new Developer('foo', 'js'); 

उदाहरण में: यहाँ मैं आपको एक उदाहरण देता कर सकते हैं। जैसा कि आप console.log परिणाम this से देख सकते हैं Developer से आता है। विधि call विधि के पहले तर्क के साथ हम उस संदर्भ को निर्दिष्ट करते हैं जिसके साथ फ़ंक्शन को कॉल किया जाएगा।

यदि आप this का उपयोग नहीं करते हैं तो बस आपके द्वारा बनाई गई संपत्ति स्थानीय चर होगी। जैसा कि आप जानते हैं कि जावास्क्रिप्ट में कार्यात्मक दायरा है इसलिए यही वैरिएबल स्थानीय होगा, केवल उस समारोह के लिए दृश्यमान होगा जहां इसे घोषित किया गया है (और निश्चित रूप से इसके सभी बच्चे के फ़ंक्शंस जिन्हें माता-पिता के अंदर घोषित किया गया है)। यहां एक उदाहरण दिया गया है:

function foo() { 
    var bar = 'foobar'; 
    this.getBar = function() { 
     return bar; 
    } 
} 

var f = new foo(); 
console.log(f.getBar()); //'foobar' 

यह सच है जब आप var कीवर्ड का उपयोग करते हैं। इसका अर्थ यह है कि यदि आप var दुर्भाग्य से bar भूल गए हैं तो आप bar को स्थानीय चर के रूप में परिभाषित कर रहे हैं।

function foo() { 
    bar = 'foobar'; 
    this.getBar = function() { 
     return bar; 
    } 
} 

var f = new foo(); 
console.log(window.bar); //'foobar' 

वास्तव में स्थानीय गुंजाइश गोपनीयता और कैप्सूलीकरण जो OOP का सबसे बड़ा लाभ में से एक हैं प्राप्त करने के लिए आप कर सकते हैं।

रियल दुनिया उदाहरण:

function ShoppingCart() { 
    var items = []; 

    this.getPrice = function() { 
     var total = 0; 
     for (var i = 0; i < items.length; i += 1) { 
      total += items[i].price; 
     } 
     return total; 
    } 

    this.addItem = function (item) { 
     items.push(item); 
    } 

    this.checkOut = function() { 
     var serializedItems = JSON.strigify(items); 
     //send request to the server... 
    } 
} 

var cart = new ShoppingCart(); 
cart.addItem({ price: 10, type: 'T-shirt' }); 
cart.addItem({ price: 20, type: 'Pants' }); 
console.log(cart.getPrice()); //30 

एक और जावास्क्रिप्ट गुंजाइश के लाभों के बारे उदाहरण Module Pattern है। मॉड्यूल पैटर्न में आप जावास्क्रिप्ट के स्थानीय कार्यात्मक दायरे का उपयोग करके गोपनीयता का अनुकरण कर सकते हैं। इस दृष्टिकोण के साथ आप निजी संपत्तियों और विधियों दोनों हो सकते हैं।

var module = (function { 

    var privateProperty = 42; 

    function privateMethod() { 
     console.log('I\'m private'); 
    } 
    return { 

     publicMethod: function() { 
      console.log('I\'m public!'); 
      console.log('I\'ll call a private method!'); 
      privateMethod(); 
     }, 

     publicProperty: 1.68, 

     getPrivateProperty: function() { 
      return privateProperty; 
     }, 

     usePublicProperty: function() { 
      console.log('I\'ll get a public property...' + this.publicProperty); 
     } 

    } 
}()); 

module.privateMethod(); //TypeError 
module.publicProperty(); //1.68 
module.usePublicProperty(); //I'll get a public property...1.68 
module.getPrivateProperty(); //42 
module.publicMethod(); 
/* 
* I'm public! 
* I'll call a private method! 
* I'm private 
*/ 

अनाम प्रक्रियाएं लपेटकर parentless साथ एक छोटी सी अजीब वाक्य रचना नहीं है लेकिन इस समय के लिए इसे भूल जाओ (यह सिर्फ समारोह के बाद यह प्रारंभ किया जा रहा है क्रियान्वित की गई हैं): यहाँ एक उदाहरण है। कार्यक्षमता को उपयोग के उदाहरण से देखा जा सकता है लेकिन लाभ मुख्य रूप से एक साधारण सार्वजनिक इंटरफ़ेस प्रदान करने से जुड़े होते हैं जो आपको सभी कार्यान्वयन विवरणों के साथ संलग्न नहीं करता है। पैटर्न के बारे में अधिक विस्तृत स्पष्टीकरण के लिए आप ऊपर दिए गए लिंक को देख सकते हैं।


मुझे आशा है कि this साथ :-) जानकारी मैं आपको जावास्क्रिप्ट की कुछ बुनियादी विषयों को समझने के लिए मदद की।

3
function Foo() { 
    this.bar = 0; 
    this.getBar = function() { return this.bar }; 
} 

जब आप new कीवर्ड के साथ ऊपर समारोह कहते हैं - इस तरह ...

var foo = new Foo(); 

... - कुछ बातें होती हैं:

1) एक वस्तु
बनाई गई है 2) फ़ंक्शन को this उस ऑब्जेक्ट का संदर्भ देने वाले कीवर्ड के साथ निष्पादित किया गया है।
3) वह वस्तु वापस आ गई है।

{ 
    bar: 0, 
    getBar: function() { return this.bar; } 
}; 

क्यों नहीं है, तो, सिर्फ इस कार्य करें::

var foo = { 
    bar: 0, 
    getBar: function() { return this.bar; } 
}; 

आप होगा, यह करता है, तो सिर्फ इतना है कि एक साधारण वस्तु

foo, तो, इस वस्तु बन जाता है।

लेकिन एक कन्स्ट्रक्टर (जिसे इसे कहा जाता है) के साथ एक ऑब्जेक्ट बनाना, हमें "समान" ऑब्जेक्ट्स बनाने में एक बड़ा फायदा देता है।

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

function Foo(bar, bob) { 
    this.bar = bar; 
    this.bob = bob; 
} 

Foo.prototype.calculate = function() { 
    // 'this' points not to the 'prototype' object 
    // as you could've expect, but to the objects 
    // created by calling Foo with the new keyword. 
    // This is what makes it work. 
    return this.bar - this.bob; 
}; 

var foo1 = new Foo(9, 5); 
var foo2 = new Foo(13, 3); 
var result1 = foo1.calculate(); 
var result2 = foo2.calculate(); 

console.log(result1); //logs 4 
console.log(result2); //logs 10 

यही है!

1

इस, वस्तुओं (चर या कार्यों) की एक सार्वजनिक उपयोग संशोधक की तरह है, जबकि वर निजी उपयोग संशोधक

उदाहरण

var x = {}; 
x.hello = function(){ 
    var k = 'Hello World'; 
    this.m = 'Hello JavaScript'; 
} 

var t = new x.hello(); 
console.log(t.k); //undefined 
console.log(t.m); //Hello JavaScript