2012-04-10 15 views
14

में बंद करके परिवर्तनीय कैप्चर को समझना मानक के अलावा जावास्क्रिप्ट में परिवर्तनीय कैप्चर पर एक निश्चित स्रोत है (यह मानक पढ़ने के लिए दर्द है)?जावास्क्रिप्ट/नोड

निम्नलिखित कोड i में मूल्य से कॉपी किया जाता है:

for (var i = 0; i < 10; i++) 
{ 
    (function (i) 
    { 
     process.nextTick(function() 
     { 
      console.log(i) 
     }) 
    }) (i) 
} 

तो यह 1..10 प्रिंट करता है। process.nextTick नोड में setTimeout(f,0) का एक एनालॉग है।

लेकिन अगले कोड में मैं नहीं लगता है कॉपी करने के लिए:

for (var i = 0; i < 10; i++) 
{ 
     var j = i 
     process.nextTick(function() 
     { 
      console.log(j) 
     }) 
} 

यह 9 10 बार प्रिंट करता है। क्यूं कर? कैप्चर करने के इस ठोस मामले को समझाने के बजाय मुझे संदर्भ/सामान्य लेख में अधिक दिलचस्पी है।

उत्तर

6

मेरे पास कोई आसान संदर्भ नहीं है। लेकिन नीचे की रेखा है: सबसे पहले, आप स्पष्ट रूप से i में अज्ञात फ़ंक्शन में गुजर रहे हैं, जो एक नया दायरा बनाता है। आप i या j के लिए दूसरे में एक नया दायरा नहीं बना रहे हैं। साथ ही, जावास्क्रिप्ट हमेशा वैरिएबल को कैप्चर करता है, मानों पर नहीं। तो आप भी मुझे संशोधित करने में सक्षम होंगे।

जावास्क्रिप्ट var कीवर्ड में कार्यक्षेत्र है, ब्लॉक दायरा नहीं है। तो लूप के लिए एक गुंजाइश नहीं बना है।

एक नोट के रूप में, गैर-मानक let कीवर्ड में स्थानीय दायरा है।

+0

यह स्पष्ट नहीं है कि मैं क्यों j – nponeccop

+0

@nponeccop के लिए एक नया गुंजाइश नहीं बना रहा हूं, जावास्क्रिप्ट समारोह गुंजाइश है। –

+0

मैं टेबल के खिलाफ अपना सिर मार रहा हूं। यह नहीं पता था कि, यह माना जाता है कि यह सी ++ या पर्ल या हास्केल है :) आकर्षक – nponeccop

4

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

मुझे इस विषय पर किसी भी निश्चित लेखन के बारे में पता नहीं है।

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

जब आप इस तरह के रूप में एक चर घोषित अपने var j = i; कुछ समारोह की शुरुआत, जावास्क्रिप्ट समारोह के शीर्ष करने के परिभाषा फहराते हैं और अपने कोड इस के बराबर हो जाता है के अलावा अन्य स्थान पर:

var j; 
for (var i = 0; i < 10; i++) 
{ 
     j = i; 
     process.nextTick(function() 
     { 
      console.log(j) 
     }) 
} 

यह variable hoisting कहा जाता है और यह एक शब्द है जिसे आप Google के बारे में अधिक पढ़ना चाहते हैं। लेकिन, मुद्दा यह है कि केवल फ़ंक्शन स्कोप है इसलिए किसी फ़ंक्शन में कहीं भी घोषित एक चर को वास्तव में फ़ंक्शन के शीर्ष पर घोषित किया जाता है और फिर फ़ंक्शन में कहीं भी असाइन किया जाता है।

+0

आपकी स्थिति पर अधिक जानकारी के साथ मेरा उत्तर अपडेट किया गया। – jfriend00

4

जावास्क्रिप्ट में कार्य करता है लगा चर जो इस तरह से अपने स्वयं के बाहर एक दायरे में परिभाषित किया गया है कि वे चर, नहीं किसी विशेष समय पर अपने मूल्य का एक स्नैपशॉट करने के लिए एक "जीवित" संदर्भ है।

तो अपने दूसरे उदाहरण में, आप दस अनाम प्रक्रियाएं (process.nextTick(function(){...}) में) जो संलग्न बनाने चर j (और i है, जो हमेशा एक ही मूल्य जब गुमनाम समारोह बनाई गई है है)। के बाद पर के मान का उपयोग प्रत्येक बाहरी फ़ंक्शन पूरी तरह से चलाया जाता है, इसलिए j=i=10 प्रत्येक कार्य को कॉल किया जाता है। यही है, पहले आपका फॉर-लूप पूरी तरह से चलता है, फिर आपके अज्ञात फ़ंक्शन चलाते हैं और j के मान का उपयोग करते हैं, जो पहले से ही 10 पर सेट है!

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

कुछ हद तक अपना पहला उदाहरण स्पष्ट करने के लिए, x ((function (x) { process.nextTick(...); })(i)) नामक तर्क का उपयोग करने के लिए अनाम रैपर फ़ंक्शन को बदलने का प्रयास करें। यहां हम स्पष्ट रूप से देखते हैं कि x गुमनाम फ़ंक्शन कहने के समय i में मान लेता है, इसलिए यह प्रत्येक मान को फॉर-लूप (1..10) में प्राप्त करेगा।

+0

संलग्न संदर्भ को बनाए रखने के बजाय मूल्य को कैप्चर करने का सबसे अच्छा अभ्यास समाधान क्या है? –

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

  • कोई संबंधित समस्या नहीं^_^