पार्टी के लिए थोड़ा देर से, लेकिन मैं आज इस मुद्दे को खोज रहा था और देखा कि बहुत से उत्तर पूरी तरह से संबोधित नहीं करते हैं कि जावास्क्रिप्ट स्कोप्स का इलाज कैसे करता है, जो अनिवार्य रूप से यह उबाल है।
तो जैसा कि कई अन्य ने उल्लेख किया है, समस्या यह है कि आंतरिक फ़ंक्शन समान i
चर का संदर्भ दे रहा है । तो क्यों न हम सिर्फ एक नया स्थानीय चर बनायें, और इसके बजाय इसके भीतर के फंक्शन का संदर्भ हो?
//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};
var funcs = {};
for (var i = 0; i < 3; i++) {
var ilocal = i; //create a new local variable
funcs[i] = function() {
console.log("My value: " + ilocal); //each should reference its own local variable
};
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
पहले की तरह, जहां प्रत्येक आंतरिक फ़ंक्शन को सौंपे गए अंतिम मान का i
आउटपुट दिया गया था , अब प्रत्येक आंतरिक फ़ंक्शन केवल दिए गए अंतिम मान को आउटपुट करता है ilocal
। लेकिन क्या प्रत्येक पुनरावृत्ति का अपना नहीं है ilocal
?
पता चला, यह मुद्दा है। प्रत्येक पुनरावृत्ति समान दायरे को साझा कर रही है, इसलिए पहले के बाद प्रत्येक पुनरावृत्ति केवल ओवरराइटिंग है ilocal
। से MDN :
महत्वपूर्ण: जावास्क्रिप्ट में ब्लॉक स्कोप नहीं है। एक ब्लॉक के साथ पेश किए गए वेरिएबल्स को फ़ंक्शन या स्क्रिप्ट से अलग किया जाता है, और उन्हें सेट करने के प्रभाव ब्लॉक से परे बने रहते हैं। दूसरे शब्दों में, ब्लॉक स्टेटमेंट एक दायरे का परिचय नहीं देते हैं। यद्यपि "स्टैंडअलोन" ब्लॉक मान्य सिंटैक्स हैं, आप जावास्क्रिप्ट में स्टैंडअलोन ब्लॉक का उपयोग नहीं करना चाहते हैं, क्योंकि वे ऐसा नहीं करते हैं जो आप सोचते हैं कि वे करते हैं, अगर आपको लगता है कि वे सी या जावा में ऐसे ब्लॉक जैसे कुछ भी करते हैं।
जोर के लिए दोहराया:
जावास्क्रिप्ट में ब्लॉक स्कोप नहीं है। एक ब्लॉक के साथ पेश किए गए वेरिएबल्स को फ़ंक्शन या स्क्रिप्ट से अलग किया जाता है
ilocal
प्रत्येक पुनरावृति में घोषित करने से पहले हम इसे देख सकते हैं :
//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};
var funcs = {};
for (var i = 0; i < 3; i++) {
console.log(ilocal);
var ilocal = i;
}
यही कारण है कि यह बग इतना मुश्किल है। भले ही आप एक चर redeclaring कर रहे हैं, जावास्क्रिप्ट एक त्रुटि फेंक नहीं होगा, और JSLint भी एक चेतावनी फेंक नहीं होगा। यही कारण है कि इसे हल करने का सबसे अच्छा तरीका क्लोजर का लाभ उठाना है, जो अनिवार्य रूप से यह विचार है कि जावास्क्रिप्ट में, आंतरिक कार्यों में बाहरी चर तक पहुंच होती है, क्योंकि आंतरिक स्कोप बाहरी स्कोप को "घेरते हैं"।
इसका मतलब यह भी है कि आंतरिक फ़ंक्शन बाहरी चर को पकड़ते हैं और उन्हें जीवित रखते हैं, भले ही बाहरी फ़ंक्शन वापस आ जाए। इसका उपयोग करने के लिए, हम एक रैपर फ़ंक्शन को शुद्ध रूप से बनाने और कॉल करने के लिए विशुद्ध रूप से एक नया स्कोप बनाते हैं, नए दायरे में घोषित करते हैं ilocal
, और एक आंतरिक फ़ंक्शन का उपयोग करते हैं ilocal
(नीचे अधिक विवरण):
//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};
var funcs = {};
for (var i = 0; i < 3; i++) {
funcs[i] = (function() { //create a new scope using a wrapper function
var ilocal = i; //capture i into a local var
return function() { //return the inner function
console.log("My value: " + ilocal);
};
})(); //remember to run the wrapper function
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
आवरण फ़ंक्शन के अंदर आंतरिक फ़ंक्शन का निर्माण आंतरिक फ़ंक्शन को एक निजी वातावरण देता है जो केवल इसे एक्सेस कर सकता है, एक "क्लोजर"। इस प्रकार, हर बार जब हम रैपर फ़ंक्शन को कॉल करते हैं, तो हम एक नया आंतरिक फ़ंक्शन बनाते हैं, जिसके पास स्वयं का अलग वातावरण होता है, यह सुनिश्चित करता है कि ilocal
चर एक दूसरे से टकराते नहीं हैं और ओवरराइट करते हैं। कुछ मामूली अनुकूलन अंतिम उत्तर देते हैं जो कई अन्य SO उपयोगकर्ताओं ने दिए:
//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};
var funcs = {};
for (var i = 0; i < 3; i++) {
funcs[i] = wrapper(i);
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
//creates a separate environment for the inner function
function wrapper(ilocal) {
return function() { //return the inner function
console.log("My value: " + ilocal);
};
}
अपडेट करें
ES6 अब मुख्यधारा के साथ, अब हम let
ब्लॉक-स्कोप किए गए चर बनाने के लिए नए कीवर्ड का उपयोग कर सकते हैं :
//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '<p>' + msg + '</p>';};
var funcs = {};
for (let i = 0; i < 3; i++) { // use "let" to declare "i"
funcs[i] = function() {
console.log("My value: " + i); //each should reference its own local variable
};
}
for (var j = 0; j < 3; j++) { // we can use "var" here without issue
funcs[j]();
}
देखो अब कितना आसान है! अधिक जानकारी के लिए इस उत्तर को देखें , जो मेरी जानकारी के आधार पर है।
funcs
यदि आप संख्यात्मक सूचकांकों का उपयोग कर रहे हैं, तो आप निश्चित रूप से एक सरणी नहीं बनना चाहते हैं? बिलकुल चौकन्ना।