Closures ও this
Closure কী, কেন দরকার, lexical scope, this-binding, call/apply/bind, arrow vs regular this — বাংলায়।
Closure হলো JavaScript-এর সবচেয়ে গভীর ও দরকারি ধারণা — inner function তার outer function-এর scope মনে রাখে। আর `this` হলো কনটেক্সট — যেভাবে ফাংশন কল হয় সেই অনুযায়ী বদলায়। দুটোই interview ও production-এর হিট টপিক।
Closure কী?
একটি ফাংশন অন্য ফাংশনের ভেতরে তৈরি হলে, ভেতরেরটা বাইরের scope-এর ভেরিয়েবল মনে রাখে — এমনকি বাইরের ফাংশন শেষ হয়ে যাওয়ার পরও। এই মনে রাখার mechanism-ই closure।
সহজ উদাহরণ
function outer() {
let count = 0;
return function inner() {
count++;
return count;
};
}
const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3outer() শেষ হয়ে গেলেও counter-কে কল করলে count বেঁচে আছে — কারণ inner তার lexical scope ধরে রেখেছে। প্রতিবার outer() ডাকলে নতুন আলাদা count তৈরি হয়।
কেন closure দরকার
closure-এর কাজ — নিজস্ব state গোপন রাখা, factory বানানো, debounce/memoization-এর মতো নিজস্ব ডেটা, আর React-এর useEffect নির্ভরশীল।
function createBankAccount(initial) {
let balance = initial;
return {
deposit(amount) {
balance += amount;
},
getBalance() {
return balance;
},
};
}
const account = createBankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
// console.log(account.balance); // undefined — private!Lexical scope
const city = "ঢাকা";
function readCity() {
// যেখানে লেখা হয়েছে সেখান থেকে খোঁজা শুরু হয়
console.log(city);
}
readCity(); // ঢাকাভেরিয়েবল খোঁজা হয় যেভাবে কোড দেখতে দাঁড়ায় — এটি lexical scope। closure এই lexical scope-কে ধরে রাখে।
this — কে আছে?
this হলো ফাংশনের calling context — কে ফাংশনটিকে ডাকছে। চারটি প্রধান নিয়ম:
// 1. method call — object-টি
const user = {
name: "রহিম",
greet() {
return this.name;
},
};
console.log(user.greet()); // রহিম
// 2. plain call — global/undefined
function show() {
return this;
}
console.log(show() === window); // true (browser)
// 3. arrow — lexical (নিজের this নেই)
const arrowUser = {
name: "করিম",
greet: () => this, // বাইরের scope-এর this
};
console.log(arrowUser.greet() === window); // truecall, apply, bind
function introduce(city) {
return `${this.name} — ${city}`;
}
const person = { name: "সুমন" };
// call — অবিলম্বে, argument আলাদা
console.log(introduce.call(person, "ঢাকা")); // সুমন — ঢাকা
// apply — অবিলম্বে, array হিসেবে
console.log(introduce.apply(person, ["চট্টগ্রাম"])); // সুমন — চট্টগ্রাম
// bind — নতুন বাঁধা ফাংশন
const bound = introduce.bind(person, "খুলনা");
console.log(bound()); // সুমন — খুলনাcall/apply সাথে সাথে runs; apply array-র argument নেয়। bind নতুন ফাংশন দেয় যেখানে this স্থায়ী — ইভেন্ট হ্যান্ডলারের জন্য সবচেয়ে দরকারি।
apply-এর উদাহরণ
const numbers = [3, 1, 4, 1, 5];
const maxNum = Math.max.apply(null, numbers);
console.log(maxNum); // 5
// আধুনিক পছন্দ: spread
const max2 = Math.max(...numbers);
console.log(max2); // 5Arrow vs Regular — this
const obj = {
value: 10,
regular: function () {
return this.value; // obj
},
arrow: () => this.value, // বাইরের this
};
console.log(obj.regular()); // 10
console.log(obj.arrow()); // undefinedregular: this = calling context। arrow: নিজের this নেই, lexical scope থেকে নেয় — তাই method-এ arrow এড়িয়ে চলুন, কিন্তু event callback-এ arrow সুবিধা।
Common mistakes
// destructuring-এ this হারানো
const user = { name: "রহিম", greet() { return this.name; } };
const { greet } = user;
// console.log(greet()); // this হারিয়ে undefined
const fixed = user.greet.bind(user);
console.log(fixed()); // রহিম
// event listener-এ
button.addEventListener("click", user.greet.bind(user));
button.addEventListener("click", () => user.greet());| প্রশ্ন | উত্তর |
|---|---|
| Closure কী? | inner function-এর outer scope মনে রাখার ক্ষমতা |
| কেন দরকার? | state গোপন, factory, debounce, React |
| call vs apply? | call: আলাদা argument; apply: array |
| bind কখন? | ইভেন্ট-এ this স্থায়ী করতে |
| arrow + this? | lexical — নিজের this নেই |
this কোন ফাংশনটা লিখেছে বা কোন object-এর property তা নয়, যেভাবে call করা হয়েছে তার অনুযায়ী — সন্দেহ হলে কনসোলে চেক করুন।
কমন প্রশ্ন: "Closure কী এবং কোথায় ব্যবহার হয়?" — উপরের counter/private account উদাহরণ মনে রাখলে উত্তর পরিপূর্ণ হবে।
একটি temperature converter factory লিখুন: createConverter(offset) — প্রতিটি instance নিজের offset মনে রাখবে (closure)।