Kodokon kodokon.com

क्लोज़र और लेक्सिकल स्कोप

समझें कि क्लोज़र किस तरह वेरिएबल को कैप्चर करते हैं, ताकि आप स्टेट को एनकैप्सुलेट कर सकें और स्कोपिंग की भूलों से बच सकें।

9 मिनट · 3 प्रश्न

इस पाठ को Kodokon में खोलें

क्लोज़र कोई अजीबोगरीब जुगाड़ नहीं है: यह वह तंत्र है जिससे कोई फंक्शन उस लेक्सिकल स्कोप तक पहुँच बनाए रखता है जहाँ वह परिभाषित किया गया था, न कि जहाँ उसे कॉल किया जाता है। इंजन वैल्यू की कॉपी नहीं बनाता: यह लेक्सिकल एनवायरनमेंट का एक जीवंत रेफरेंस बनाए रखता है। इसलिए एक ही फैक्ट्री को दो बार कॉल करने पर दो स्वतंत्र एनवायरनमेंट बनते हैं, जो क्लोज़र को इस भाषा का सबसे हल्का एनकैप्सुलेशन टूल बनाता है।

JAVASCRIPT
function createCounter() {
  let count = 0;
  return {
    increment: () => ++count,
    reset: () => { count = 0; },
  };
}
const counterA = createCounter();
const counterB = createCounter();
counterA.increment();
counterA.increment();
console.log(counterA.increment()); // 3
console.log(counterB.increment()); // 1
प्राइवेट स्टेट: count केवल लौटाए गए मेथड्स के ज़रिए ही पहुँच योग्य है।

वास्तविक दुनिया का क्लासिक जाल: var अपने आसपास के फंक्शन से बँधा होता है, ब्लॉक से नहीं। किसी लूप के भीतर, हर क्लोज़र तब एक ही वेरिएबल को कैप्चर कर लेता है। let के साथ, हर इटरेशन एक ताज़ा लेक्सिकल एनवायरनमेंट बनाता है, इसलिए हर कैप्चर अलग होता है। इसके साथ ही जुड़ता है टेम्पोरल डेड ज़ोन (TDZ): कोई let या const वेरिएबल ब्लॉक में प्रवेश करते ही मौजूद हो जाता है, पर उसकी घोषणा से पहले उसे पढ़ने पर ReferenceError फेंकता है।

JAVASCRIPT
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 0); // 3, 3, 3
}
for (let j = 0; j < 3; j++) {
  setTimeout(() => console.log(j), 0); // 0, 1, 2
}
var एक ही बाइंडिंग साझा करता है; let हर इटरेशन के लिए एक बनाता है।

पैटर्न की दृष्टि से, क्लोज़र मेमोइज़ेशन और मॉड्यूल पैटर्न की नींव हैं। किसी क्लास की तुलना में, क्लोज़र आपको this या प्रोटोटाइप के बिना असली प्राइवेसी देता है, बस इसकी कीमत यह है कि जब आप हज़ारों इंस्टेंस बनाते हैं तो मेमोरी उपयोग थोड़ा अधिक होता है: हर इंस्टेंस अपने खुद के फंक्शन साथ लेकर चलता है।

JAVASCRIPT
function memoize(fn) {
  const cache = new Map();
  return function (key) {
    if (cache.has(key)) return cache.get(key);
    const result = fn(key);
    cache.set(key, result);
    return result;
  };
}
const square = (n) => n * n;
const fastSquare = memoize(square);
console.log(fastSquare(9)); // computed
console.log(fastSquare(9)); // read from the cache
कैश क्लोज़र के भीतर रहता है, बाहर से अदृश्य।

ज्ञान जांच

सुनिश्चित करें कि आपको इस पाठ के मुख्य बिंदु याद हैं।

  1. किसी for (var i = ...) लूप में, लूप के भीतर बनाए गए तीन setTimeout कॉलबैक क्या लॉग करते हैं?
    • 0, 1, 2 क्योंकि हर कॉलबैक अपनी खुद की वैल्यू कैप्चर करता है
    • 3, 3, 3 क्योंकि वे सभी i की एक ही बाइंडिंग साझा करते हैं
    • undefined तीन बार क्योंकि लूप के बाद i नष्ट हो जाता है
  2. जहाँ क्लोज़र परिभाषित हुआ था, वहाँ के एनवायरनमेंट से क्लोज़र ठीक-ठीक क्या बनाए रखता है?
    • बनने के समय की वैल्यू की एक जमी हुई कॉपी
    • कैप्चर किए गए वेरिएबल का एक जीवंत रेफरेंस
    • केवल आसपास के फंक्शन के पैरामीटर
    • कुछ नहीं: फंक्शन के लौटते ही स्कोप नष्ट हो जाता है
  3. createCounter इस बात की गारंटी क्यों देता है कि count प्राइवेट बना रहे?
    • क्योंकि let वेरिएबल को इम्यूटेबल बना देता है
    • क्योंकि count केवल लौटाए गए फंक्शन्स के ज़रिए ही पहुँच योग्य है, जो अकेले उसके स्कोप को कैप्चर करते हैं
    • क्योंकि फैक्ट्री के लौटने के बाद इंजन count को हटा देता है