संक्षेप में जावास्क्रिप्ट क्लोजर एक फ़ंक्शन को एक वैरिएबल तक पहुंचने की अनुमति देता है जो एक लेक्सिकल-पैरेंट फ़ंक्शन में घोषित किया गया है ।
आइए अधिक विस्तृत विवरण देखें। क्लोजर को समझने के लिए यह समझना महत्वपूर्ण है कि जावास्क्रिप्ट कैसे चरता है।
कार्यक्षेत्र
जावास्क्रिप्ट स्कोप में कार्यों के साथ परिभाषित किया गया है। हर फंक्शन एक नए दायरे को परिभाषित करता है।
निम्नलिखित उदाहरण पर विचार करें;
function f()
{//begin of scope f
var foo='hello'; //foo is declared in scope f
for(var i=0;i<2;i++){//i is declared in scope f
//the for loop is not a function, therefore we are still in scope f
var bar = 'Am I accessible?';//bar is declared in scope f
console.log(foo);
}
console.log(i);
console.log(bar);
}//end of scope f
कॉलिंग एफ प्रिंट्स
hello
hello
2
Am I Accessible?
आइए अब उस मामले पर विचार करें जो हमारे पास एक फ़ंक्शन है g
जिसे दूसरे फ़ंक्शन के भीतर परिभाषित किया गया है f
।
function f()
{//begin of scope f
function g()
{//being of scope g
/*...*/
}//end of scope g
/*...*/
}//end of scope f
हम फोन करेगा शाब्दिक माता पिता के । जैसा कि पहले बताया गया है कि अब हमारे पास 2 स्कोप हैं; दायरा और दायरा ।f
g
f
g
लेकिन एक गुंजाइश दूसरे दायरे के "भीतर" है, तो क्या पैरेंट फंक्शन के दायरे के चाइल्ड फंक्शन पार्ट का स्कोप है? मूल फ़ंक्शन के दायरे में घोषित चर के साथ क्या होता है; क्या मैं उन्हें चाइल्ड फंक्शन के दायरे से एक्सेस कर पाऊंगा? ठीक यही वह जगह है जहाँ बंद कदम अंदर है।
बंद
जावास्क्रिप्ट में फ़ंक्शन g
न केवल दायरे में घोषित किसी भी चर का उपयोग कर सकता है, g
बल्कि मूल फ़ंक्शन के दायरे में घोषित किसी भी चर का उपयोग कर सकता है f
।
निम्नलिखित पर विचार करें;
function f()//lexical parent function
{//begin of scope f
var foo='hello'; //foo declared in scope f
function g()
{//being of scope g
var bar='bla'; //bar declared in scope g
console.log(foo);
}//end of scope g
g();
console.log(bar);
}//end of scope f
कॉलिंग एफ प्रिंट्स
hello
undefined
आइए रेखा को देखें console.log(foo);
। इस बिंदु पर हम दायरे में हैं g
और हम उस वेरिएबल को एक्सेस करने की कोशिश करते हैं foo
जो स्कोप में घोषित किया गया है f
। लेकिन जैसा कि पहले कहा गया है कि हम एक लेक्सिकल पैरेंट फंक्शन में घोषित किसी भी वैरिएबल को एक्सेस कर सकते हैं जो कि यहाँ मामला है; g
का शाब्दिक माता-पिता है f
। इसलिए hello
छपा है।
आइए अब रेखा को देखें console.log(bar);
। इस बिंदु पर हम दायरे में हैं f
और हम उस वेरिएबल को एक्सेस करने की कोशिश करते हैं bar
जो स्कोप में घोषित किया गया है g
। bar
वर्तमान दायरे में घोषित नहीं किया गया है और फ़ंक्शन g
माता-पिता का नहीं है f
, इसलिए bar
अपरिभाषित है
वास्तव में हम एक लेक्सिकल "ग्रैंड पैरेंट" फ़ंक्शन के दायरे में घोषित चर भी एक्सेस कर सकते हैं। इसलिए यदि फ़ंक्शन h
के भीतर कोई फ़ंक्शन परिभाषित होगाg
function f()
{//begin of scope f
function g()
{//being of scope g
function h()
{//being of scope h
/*...*/
}//end of scope h
/*...*/
}//end of scope g
/*...*/
}//end of scope f
तो h
सभी चर समारोह के दायरे में घोषित उपयोग करने में सक्षम हो जाएगा h
, g
और f
। यह क्लोजर के साथ किया जाता है । जावास्क्रिप्ट क्लोजर में हम लेक्सिकल पेरेंट फंक्शन में, लेक्सिकल ग्रैंड पेरेंट फंक्शन में, लेक्सिकल ग्रैंड-ग्रैंड पैरेंट फंक्शन आदि में घोषित किसी भी वैरिएबल को एक्सेस करने की अनुमति देते हैं। इसे स्कोप चेन के रूप में देखा जा सकता है ; scope of current function -> scope of lexical parent function -> scope of lexical grand parent function -> ...
अंतिम अभिभावक समारोह तक, जिसमें कोई शाब्दिक माता-पिता नहीं हैं।
खिड़की की वस्तु
वास्तव में श्रृंखला अंतिम मूल कार्य पर नहीं रुकती है। एक और विशेष गुंजाइश है; वैश्विक क्षेत्र । किसी फ़ंक्शन में घोषित नहीं होने वाले प्रत्येक चर को वैश्विक दायरे में घोषित किया जाता है। वैश्विक दायरे की दो विशिष्टताएँ हैं;
- वैश्विक दायरे में घोषित प्रत्येक चर हर जगह सुलभ है
- वैश्विक दायरे में घोषित चर
window
वस्तु के गुणों के अनुरूप हैं ।
इसलिए foo
वैश्विक दायरे में परिवर्तनशील घोषित करने के दो तरीके हैं ; या तो इसे किसी फ़ंक्शन में घोषित न करके या foo
विंडो ऑब्जेक्ट की संपत्ति सेट करके ।
दोनों प्रयास क्लोजर का उपयोग करते हैं
अब जब आपने अधिक विस्तृत विवरण पढ़ लिया है तो अब यह स्पष्ट हो सकता है कि दोनों समाधान क्लोजर का उपयोग करते हैं। लेकिन यह सुनिश्चित करने के लिए, आइए एक प्रमाण बनाते हैं।
आइए एक नई प्रोग्रामिंग भाषा बनाएं; जावास्क्रिप्ट-नहीं-बंद। जैसा कि नाम से पता चलता है, जावास्क्रिप्ट-नो-क्लोजर जावास्क्रिप्ट के समान है, सिवाय इसके कि यह क्लोजर का समर्थन नहीं करता है।
दूसरे शब्दों में;
var foo = 'hello';
function f(){console.log(foo)};
f();
//JavaScript-No-Closure prints undefined
//JavaSript prints hello
ठीक है, चलो देखते हैं कि जावास्क्रिप्ट-नो-क्लोजर के साथ पहले समाधान के साथ क्या होता है;
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}, 1000)
})();
}
इसलिए यह undefined
जावास्क्रिप्ट-नो-क्लोजर में 10 बार प्रिंट होगा ।
इसलिए पहला समाधान क्लोजर का उपयोग करता है।
चलो दूसरा समाधान देखें;
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2); //i2 is undefined in JavaScript-No-Closure
}
})(i), 1000);
}
इसलिए यह undefined
जावास्क्रिप्ट-नो-क्लोजर में 10 बार प्रिंट होगा ।
दोनों समाधान क्लोजर का उपयोग करते हैं।
संपादित करें: यह माना जाता है कि इन 3 कोड स्निपेट को वैश्विक दायरे में परिभाषित नहीं किया गया है। अन्यथा चर foo
और i
करने के लिए बाध्य किया जाएगा window
वस्तु और इसलिए के माध्यम से सुलभ window
दोनों जावास्क्रिप्ट और जावास्क्रिप्ट-नहीं-बंद में वस्तु।