Free tutorials & notes in Hindi & English · Clean code examples 🧰 मुफ़्त PDF और फ़ोटो टूल्स →
⚡ Days 15–22 – Advanced और Async JavaScript  ·  दिन 16

दिन 16: Scope, Hoisting और Closures

⏱ 90 min📶 Intermediate🎯 100% self-study
दिन 16 / 30

✅ आज आप सीखेंगे

  • Global, function और block scope; scope chain
  • Hoisting: var बनाम let/const बनाम function declarations, TDZ
  • Closures: याद रखने वाले functions
  • असली उपयोग: private state, factories, memoise, once
  • मशहूर var-in-a-loop bug

🏢 असली दुनिया में

“Closures समझाइए” India में service companies से product startups तक सबसे ज़्यादा पूछे जाने वाले JavaScript interview सवालों में है। यह व्यावहारिक भी है: हर event handler, timer और React hook closures पर टिका है। आज आप इसे इतना समझेंगे कि sweet-shop उदाहरण से समझा सकें – और 20 साल से developers को उलझाने वाला bug ठीक कर सकें।

Scope और scope chain

JavaScript
const shop = 'Sharma Sweets';                 // global scope

function makeInvoice(orderNo) {              // function scope
  const prefix = 'INV';
  if (orderNo > 1000) {
    const series = 'B';                      // block scope
    return `${shop} ${prefix}-${series}${orderNo}`;   // looks outward: block → function → global
  }
  return `${shop} ${prefix}-${orderNo}`;
}
console.log(makeInvoice(42));
console.log(makeInvoice(1042));
console.log(typeof prefix, typeof series);  // not visible outside
Sharma Sweets INV-42 Sharma Sweets INV-B1042 undefined undefined
Block scope { }Function scopeModule / script scopeGlobal scopeनहीं मिला → ReferenceError
JavaScript variable को अंदर से बाहर की ओर ढूँढता है

Hoisting और temporal dead zone

JavaScript
console.log(greet('Riya'));          // ✅ function declarations are hoisted with their body
function greet(n) { return 'Namaste ' + n; }

console.log(oldStyle);               // undefined – var is hoisted but set to undefined
var oldStyle = 'var';

try {
  console.log(modern);               // ❌ let/const exist but are in the "temporal dead zone"
  let modern = 'let';
} catch (err) {
  console.log(err.name + ': ' + err.message);
}
Namaste Riya undefined ReferenceError: Cannot access 'modern' before initialization
DeclarationHoist होता है?Line से पहले
function name() {}हाँ, body समेतबुलाया जा सकता है
var xहाँ, undefined के रूप मेंundefined (चुपचाप bugs)
let / constहाँ, पर uninitialised (TDZ)ReferenceError
const f = () => {}const जैसाReferenceError
class A {}let जैसा (TDZ)ReferenceError

Closures: याद रखने वाले functions

JavaScript
function createCounter(label) {
  let count = 0;                       // private – nobody outside can touch it
  return function () {                 // this inner function "closes over" count and label
    count++;
    return `${label}: token #${count}`;
  };
}

const counterA = createCounter('Counter A');
const counterB = createCounter('Counter B');
console.log(counterA());
console.log(counterA());
console.log(counterB());               // separate memory for each counter
console.log(counterA());
console.log(typeof count);
Counter A: token #1 Counter A: token #2 Counter B: token #1 Counter A: token #3 undefined
🧠 एक-line परिभाषा

Closure एक function है जो उस जगह के variables के साथ बँधा है जहाँ वह बना। createCounter ख़त्म होने के बाद भी लौटाया function अपने count तक पहुँचता है – जैसे दुकान की token machine अपना नंबर ख़ुद रखती है।

Closures के असली उपयोग

JavaScript
// 1. Private state with a public API (module pattern)
function createWallet(start) {
  let balance = start;
  return {
    pay(amount) {
      if (amount > balance) return `Insufficient balance (₹${balance})`;
      balance -= amount;
      return `Paid ₹${amount}, left ₹${balance}`;
    },
    get balance() { return balance; },
  };
}
const wallet = createWallet(1000);
console.log(wallet.pay(650));
console.log(wallet.pay(500));
wallet.balance = 999999;                       // no setter → cannot be changed from outside
console.log(wallet.balance);

// 2. Function factories
const makeDiscount = percent => price => Math.round(price * (1 - percent / 100));
const diwali10 = makeDiscount(10), member5 = makeDiscount(5);
console.log(diwali10(900), member5(900));

// 3. once() – e.g. a coupon that can be applied only once
function once(fn) {
  let done = false, result;
  return (...args) => (done ? result : ((done = true), (result = fn(...args))));
}
const applyCoupon = once(code => `Coupon ${code} applied`);
console.log(applyCoupon('SWEET10'), '|', applyCoupon('AGAIN'));

// 4. Memoisation – cache slow results
function memo(fn) {
  const cache = new Map();
  return n => (cache.has(n) ? cache.get(n) + ' (cached)' : (cache.set(n, fn(n)), cache.get(n)));
}
const slowGst = memo(amount => amount * 0.05);
console.log(slowGst(2000), slowGst(2000));
Paid ₹650, left ₹350 Insufficient balance (₹350) 350 810 855 Coupon SWEET10 applied | Coupon SWEET10 applied 100 100 (cached)

क्लासिक var-in-a-loop bug

JavaScript
const withVar = [], withLet = [];
for (var i = 1; i <= 3; i++) withVar.push(() => i);   // ONE shared i for all functions
for (let j = 1; j <= 3; j++) withLet.push(() => j);   // a NEW j for every round
console.log(withVar.map(f => f()));    // [4, 4, 4] ❌
console.log(withLet.map(f => f()));    // [1, 2, 3] ✅
[ 4, 4, 4 ] [ 1, 2, 3 ]
💡 ऐसा क्यों होता है

var function-scoped है, तो तीनों closures एक ही variable याद रखते हैं, जो loop ख़त्म होने पर 4 है। let हर iteration के लिए नई binding बनाता है। आधुनिक code के let/const इस्तेमाल का यही #1 कारण है।

असली task: स्वतंत्र token counters

HTML + JavaScript
<div id="counters"></div>

<script>
function createTokenCounter(name) {
  let next = 1;                                     // private per counter
  const box = document.createElement('div');
  box.style.cssText = 'display:inline-block;margin:6px;padding:12px 16px;border:1px solid #e5e7eb;border-radius:12px;text-align:center';
  const title = document.createElement('b');
  title.textContent = name;
  const shown = document.createElement('div');
  shown.style.fontSize = '2rem';
  shown.textContent = '—';
  const btn = document.createElement('button');
  btn.textContent = 'Next token';
  btn.addEventListener('click', () => { shown.textContent = 'A' + String(next++).padStart(3, '0'); });   // closure!
  box.append(title, shown, btn);
  return box;
}
document.querySelector('#counters').append(
  createTokenCounter('Sweets counter'),
  createTokenCounter('Namkeen counter'),
  createTokenCounter('Billing'));
</script>
▶  Each click handler remembers its own “next” – three closures

🏅 आज के Job Skills

✔ Scope chain में variables खोजना✔ Hoisting व्यवहार का अनुमान और TDZ से बचना✔ Private state, factories, once और memo के लिए closures✔ var-in-a-loop bug समझाना और ठीक करना

Practice tasks

🏋️ Practice – ख़ुद करें

Task 1: createRateLimiter(limit) लिखें जो ऐसा function लौटाए जो अधिकतम limit बार चले, फिर "Too many requests" लौटाए।
Solution देखें
JavaScript
function createRateLimiter(limit) {
  let calls = 0;
  return function (action) {
    calls++;
    return calls <= limit ? `OK: ${action} (${calls}/${limit})` : 'Too many requests';
  };
}
const sendOtp = createRateLimiter(3);
['otp', 'otp', 'otp', 'otp'].forEach(a => console.log(sendOtp(a)));
OK: otp (1/3) OK: otp (2/3) OK: otp (3/3) Too many requests
Task 2: पहले output का अनुमान लगाएँ, फिर चलाएँ।
Solution देखें
JavaScript
let x = 'global';
function outer() {
  let x = 'outer';
  function inner() { return x; }
  return inner;
}
const f = outer();
x = 'changed global';
console.log(f());          // 'outer' – inner remembers outer's x, not the global one
outer
Task 3: makeMultiplier(n) factory बनाकर GST-5% और GST-12% calculator बनाएँ।

Quick quiz

🧠 Quick Quiz – ख़ुद को जाँचें

1. Closure है…
अपना scope याद रखता है।
2. let variable को उसकी line से पहले पढ़ने पर…
TDZ।
3. कौन body समेत hoist होता है?
सिर्फ़ declarations।
4. for (var i = 0; i < 3; i++) fns.push(() => i); fns[0]() लौटाता है…
साझा var।
5. Closures बनाने में मदद करते हैं…
Encapsulation।

Interview corner

💼 Interview Corner

Closure क्या है? व्यावहारिक उदाहरण दीजिए।

Closure function और उसके lexical environment का मेल है, जिससे बाहरी function के लौटने के बाद भी function बाहरी variables तक पहुँच रखता है। उदाहरण: private state वाला counter/rate-limiter, अपना item याद रखने वाले event handlers, या private cache वाला memoised function।

Hoisting समझाइए।

Compilation के दौरान declarations अपने scope में दर्ज होते हैं: function declarations पूरे, var undefined के रूप में, let/const/class uninitialised (temporal dead zone) – यानी मौजूद हैं पर declaration line से पहले पढ़े नहीं जा सकते।

सारांश

  • Variables block → function → global क्रम में खोजे जाते हैं।
  • Functions पूरे hoist; var undefined के रूप में; let/const TDZ में।
  • Closures = functions + याद रखे variables → private state, factories, once, memo।
  • साझा-var bug से बचने को loops में let।
➡️ आगे

Day 17: this, classes और object-oriented JavaScript – दोबारा उपयोगी Cart class बनाएँ।

अक्सर पूछे जाने वाले प्रश्न (FAQ)

क्या closures memory leaks करते हैं?
सिर्फ़ तब जब आप ऐसे बड़े objects के references रखें जिनकी ज़रूरत नहीं (जैसे कभी न हटाए listeners)। सामान्य closures कोई reference न रहने पर मुक्त हो जाते हैं।
React में closures कहाँ?
हर component function, event handler और hook callback props और state पर closure है – इसीलिए पुरानी value पकड़ने वाले closure से “stale state” bugs होते हैं।
← JavaScript (30 Days)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

अगला topicदिन 17: this, Classes और Object-Oriented JS आपकी प्रगति: 16 / 30 (53%) · Lesson 17 / 30 आगे बढ़ें →

यह lesson कैसा लगा?

आपकी राय से हम content और बेहतर बनाते हैं।

अपना review और सुझाव लिखें (वैकल्पिक)

Review approve होने के बाद आपका नाम और शहर इसके साथ public दिख सकते हैं। Email या phone न लिखें।

▶ CodingEasily on YouTube

Video से सीखें – आसान Hindi में

चुनी हुई video: RDBMS भाग 3 – Class XI Commerce IT

▶ Channel subscribe करें