2012-04-02 14 views
6

मैं इस पहेली को हल करने वाली जावास्क्रिप्ट ओओपी समस्या को हल करने की कोशिश कर रहा हूं।जावास्क्रिप्ट कक्षाएं और चरणीय संदर्भ

तो मैं निम्नलिखित वर्ग है:

var ClassA = function() { 
    this.initialize(); 
} 

ClassA.prototype = { 

    methods : ['alpha','beta','gama'], 

    initialize : function() { 
     for (var i in this.methods) { 
      this[this.methods[i]] = function() { 
       console.log(this.methods[i]); 
      } 
     } 
    } 
} 

var a = new ClassA(); 

जब मैं हर विधि मैं इसके बारे में नाम मुद्रित करने के लिए उम्मीद सही कहते हैं,?

a.alpha(); // returns gama ?!? 
a.beta(); // returns gama ?!? 
a.gama(); // returns gama 

लेकिन जब मेरी कक्षा इस तरह दिखता है:

var ClassB = function() { 
    this.initialize(); 
} 

ClassB.prototype = { 

    methods : ['alpha', 'beta', 'gama'], 

    initialize: function() { 
     for (var i in this.methods) { 
      this.addMethod(this.methods[i]); 
     } 
    }, 

    addMethod: function(method) { 
     this[method] = function() { 
      console.log(method); 
     } 
    } 

} 

var b = new ClassB(); 

b.alpha(); // returns alpha 
b.beta(); // returns beta 
b.gama(); // returns gama 

क्यों हो रहा है लेकिन यहाँ मैं क्या मिलता है?

+0

क्या यह [गलत तरीका] नहीं है (http://stackoverflow.com/questions/3010840/loop-through-array-in-javascript#answer-3010848) जेएस में एक सरणी के माध्यम से लूपिंग के? – PeeHaa

+0

@RepWhoringPeeHaa - हां, लूप के लिए एक सादा इस्तेमाल किया जाना चाहिए, लेकिन यह समस्या नहीं है। – nnnnnn

+0

@nnnnnn मुझे पता है कि यह एक टिप्पणी है और जवाब नहीं :-) – PeeHaa

उत्तर

6
for (var i in this.methods) { 
     this[this.methods[i]] = function() { 
      console.log(this.methods[i]); 
     } 
} 

आपकी समस्या यहां निहित है। जब यह लूप समाप्त होता है, i अंतिम तत्व है। प्रत्येक फ़ंक्शन एक ही i का उपयोग करता है, इसलिए वे सभी अंतिम तत्व हैं।

जब आप addMethod का उपयोग करते हैं तो आप सही मूल्य को "कैप्चर" करने के लिए बंद कर रहे हैं।

संपादित करें: जब आप addMethod पर कॉल करते हैं तो आप i मान का उपयोग करने के बजाय मूल्य को "प्रतिलिपि बना रहे हैं, जो प्रत्येक लूप पुनरावृत्ति के साथ बदलता है।

+0

मैं इस तरह के हर प्रश्न का उत्तर देता हूं ... http://stackoverflow.com/questions/9980209/register-onclick-events-from - गतिशील रूप से निर्मित-div-array-rails-jquery/9980579 # 9980579 –

+0

मैं उलझन में हूं ... कंसोल.लॉग सिर्फ एक और फ़ंक्शन नहीं है, और addMethod द्वारा मैं बस इसे दूसरे में लपेट रहा हूं? – drinchev

+0

@drinchev: 'console.log' यहां महत्वपूर्ण नहीं है। यहां महत्वपूर्ण क्या है, यह है कि जब आप 'addMethod' कहते हैं, तो आप प्रत्येक फ़ंक्शन में मान की प्रतिलिपि बना रहे हैं, लेकिन जब आप इसे बिना करते हैं, तो आप एक ही मान का उपयोग कर रहे हैं। (क्षमा करें अगर मैं यह अच्छी तरह से समझा नहीं रहा हूं।) –

3

अपने पहले संस्करण में:

initialize : function() { 
    for (var i in this.methods) { 
     this[this.methods[i]] = function() { 
      console.log(this.methods[i]); 
     } 
    } 
} 

तरीकों कि आप initialize सभी के अंदर बनाते हैं initialize से एक ही i चर का उल्लेख है - और initialize रन i के बाद मूल्य "gama" है, तो भले ही तरीकों में से जो की आप कॉल करते हैं कि यह i का मान है कि वे कंसोल पर लॉग ऑन करेंगे। जेएस विधि के निर्माण के समय i के वर्तमान मूल्य को संग्रहीत नहीं करता है।

जे एस प्रत्येक कार्य के लिए एक "बंद" बनाता है - चर अपने initialize समारोह में घोषित (अर्थात, i) नेस्टेड समारोह (रों) initialize के बाद भी समाप्त हो गया है के लिए दायरे में बने हुए हैं।

दूसरे संस्करण कॉल addMethod प्रत्येक विधि जोड़ने के लिए:

addMethod: function(method) { 
    this[method] = function() { 
     console.log(method); 
    } 
} 

... और इसलिए जब वे चलाते हैं वे अपने स्वयं के method पैरामीटर का "कॉपी" पर गौर करेंगे तो एक अलग बंद है, क्योंकि प्रत्येक विधि के लिए।

संपादित करें: यह प्रश्न भी देखें: How do JavaScript closures work? (कई उत्तर वहां से अधिक स्पष्ट रूप से समझाते हैं)।

1

आपको गुमनाम बंद जोड़कर अपने पहले उदाहरण ठीक कर सकते हैं:

initialize : function() { 
    for (var i in this.methods) { 
     (function (i) { // anonymous closure 
      this[this.methods[i]] = function() { 
       console.log(this.methods[i]); 
      } 
     }).call(this, i); // use .call() if you need "this" inside 
    } 
} 

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

नोट बग़ल में: कहा जाता है समारोह के अंदर this संरक्षित करने के लिए .call(this, ...) उपयोग करें, या आप var that = this कर सकते हैं, this के बजाय that का उपयोग करें और सामान्य रूप से कार्य फोन:

for (var i in this.methods) { 
    var that = this; 
    (function (i) { // anonymous closure 
     that[that.methods[i]] = function() { 
      console.log(that.methods[i]); 
     } 
    })(i); // Called normally so use "that" instead of "this"! 
} 
+1

वह पहले ही समस्या को ठीक कर चुका है, वह जानना चाहता था कि यह पहली जगह क्यों एक समस्या थी। –

+0

हां, लेकिन इसे ठीक करने का यह तरीका अधिक सरल, सरल है। – TMS

+0

मैं सहमत हूं, लेकिन यह अभी भी मूल प्रश्न का उत्तर नहीं देता है। –

0

ठीक है, सब से पहले के लिए उपयोग करना बंद कर (वस्तु में संपत्ति) Arrays पर loops। यह सभी मजेदार और गेम है जब तक कि कोई ऐरे ऑब्जेक्ट पर प्रोटोटाइप नहीं करता है जो कि पूरी तरह से उचित और बहुत उपयोगी/लोकप्रिय चीज है। इसके परिणामस्वरूप x में सरणी loops में आपके लिए कस्टम तरीकों को जोड़ा जा रहा है।

समस्या के लिए, यह वही कर रहा है जो आपने इसे संस्करण 1 में करने के लिए कहा था। समस्या यह है कि जब तक आप इसे फायर करने के लिए चारों ओर जाते हैं, तो मैं आखिरी चीज था, 'गामा'। जब आप किसी फ़ंक्शन में किसी तर्क के संदर्भ में संदर्भ पारित करते हैं, तो फ़ंक्शन मान के राज्य पर निर्भर करता है क्योंकि यह पारित किया गया था।

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