जावास्क्रिप्ट में क्लोजर: सरल भाषा में और अंदरूनी व्याख्या

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

जावास्क्रिप्ट में क्लोजर कैसे काम करते हैं: Stack Overflow के उदाहरण के साथ विश्लेषण

\n\n

यदि आपने कभी "JavaScript closures" खोजा है या Stack Overflow पर चर्चाएँ पढ़ी हैं, तो आपने निश्चित रूप से प्रसिद्ध प्रश्न देखा होगा: "How do JavaScript closures work?"। इस थ्रेड को हज़ारों बार देखा गया है और सैकड़ों उत्तर मिले हैं - सरल स्पष्टीकरण से लेकर V8 इंजन में गहराई तक। क्यों? क्योंकि क्लोजर उन अवधारणाओं में से एक है जो पहले जादू लगती है, और फिर आपका सुपर-हथियार बन जाती है।

\n\n

इस लेख में हम केवल सिद्धांत को दोहराने वाले नहीं हैं। हम जावास्क्रिप्ट के अंदर झाँकेंगे, विश्लेषण करेंगे कि मेमोरी में क्या होता है, और अंततः समझेंगे कि यह कोड ऐसा क्यों काम करता है और अन्यथा नहीं। तैयार हैं? चलिए शुरू करते हैं।

\n\n

क्लोजर क्या है? बिना अनावश्यक विस्तार के परिभाषा

\n\n

आइए सबसे महत्वपूर्ण बात से शुरू करते हैं। क्लोजर (closure) एक ऐसा फंक्शन है जो अपने बाहरी स्कोप के वेरिएबल्स को "याद" रखता है, भले ही वह बाहरी फंक्शन अपना काम पूरा कर चुका हो।

\n\n

यह एक जादू जैसा लगता है? आइए सीधे कोड पर आते हैं। यहाँ एक क्लासिक उदाहरण है जो आपको Stack Overflow पर मिलेगा:

\n\n
function createCounter() {\n    let count = 0;\n    return function() {\n        count++;\n        return count;\n    };\n}\n\nconst counter = createCounter();\nconsole.log(counter()); // 1\nconsole.log(counter()); // 2\nconsole.log(counter()); // 3
\n\n

यहाँ createCounter एक अनाम फंक्शन लौटाता है। यह आंतरिक फंक्शन वेरिएबल count को "क्लोज़" करता है। createCounter के समाप्त होने के बाद भी (हम सोचते हैं कि इसके अंदर के सभी वेरिएबल गायब हो जाने चाहिए), count जीवित रहता है और counter() के प्रत्येक कॉल पर बदलता रहता है। यही क्लोजर है।

\n\n

अंदरूनी तौर पर: लेक्सिकल एनवायरनमेंट

\n\n

यह समझने के लिए कि यह कैसे काम करता है, हमें जावास्क्रिप्ट इंजन के अंदर झाँकना होगा। प्रत्येक फंक्शन के निर्माण के समय एक छिपी हुई प्रॉपर्टी [[Environment]] होती है। यह उस लेक्सिकल एनवायरनमेंट (Lexical Environment) का संदर्भ संग्रहीत करती है जिसमें फंक्शन बनाया गया था।

\n\n

लेक्सिकल एनवायरनमेंट बस एक ऑब्जेक्ट है जिसमें शामिल है:

\n
    \n
  • एनवायरनमेंट रिकॉर्ड (Environment Record) - इस स्कोप में घोषित सभी वेरिएबल और फंक्शन।
  • \n
  • बाहरी एनवायरनमेंट (outer) का संदर्भ - पैरेंट स्कोप।
  • \n
\n\n

जब हम किसी फंक्शन को कॉल करते हैं, तो उस कॉल के लिए एक नया लेक्सिकल एनवायरनमेंट बनता है। आंतरिक फंक्शन स्कोप चेन (scope chain) के माध्यम से बाहरी फंक्शन के वेरिएबल्स तक पहुँच प्राप्त करता है।

\n\n

अपने उदाहरण पर वापस आते हैं। जब हम createCounter घोषित करते हैं, तो एक ग्लोबल लेक्सिकल एनवायरनमेंट बनता है। इसके अंदर - वेरिएबल createCounter (फंक्शन) और counter (अभी undefined)।

\n\n

जब हम createCounter() कॉल करते हैं:

\n
    \n
  1. इस कॉल के लिए एक नया लेक्सिकल एनवायरनमेंट बनता है। इसमें वेरिएबल count = 0 है।
  2. \n
  3. एक अनाम फंक्शन बनता है। इसका [[Environment]] वर्तमान एनवायरनमेंट (जहाँ count रहता है) को इंगित करता है।
  4. \n
  5. फंक्शन लौटाया जाता है और counter को असाइन किया जाता है।
  6. \n
\n\n

और यहाँ सबसे दिलचस्प बात है: createCounter समाप्त हो गया, लेकिन इसका लेक्सिकल एनवायरनमेंट गार्बेज कलेक्टर द्वारा हटाया नहीं जाता! क्योंकि इस पर एक संदर्भ है - आंतरिक फंक्शन का [[Environment]]। एनवायरनमेंट मेमोरी में तब तक "लटका" रहता है जब तक फंक्शन counter स्वयं मौजूद है।

\n\n

अब हर बार जब हम counter() कॉल करते हैं, तो इस कॉल के लिए एक नया एनवायरनमेंट बनता है, जो चेन के माध्यम से count वाले उस पुराने एनवायरनमेंट को देखता है। इस प्रकार हमें "याद रखने" का प्रभाव मिलता है।

\n\n

यह क्यों महत्वपूर्ण है? वास्तविक परिदृश्य

\n\n

क्लोजर केवल एक अकादमिक अवधारणा नहीं हैं। इनका उपयोग हर जगह किया जाता है। आइए कुछ वास्तविक उदाहरणों पर नज़र डालते हैं।

\n\n

1. प्राइवेट वेरिएबल (एनकैप्सुलेशन)

\n\n

जावास्क्रिप्ट में कोई वास्तविक

ब्लॉग

पुस्तक अनुशंसाएँ