JavaScript ক্লোজার এবং স্কোপ সহজভাবে ব্যাখ্যা
আপনি একটি JavaScript ফাংশন লিখছেন যা আরেকটি ফাংশন রিটার্ন করে। ভেতরের ফাংশনটি বাইরের ফাংশনের একটি ভেরিয়েবল ব্যবহার করে, কিন্তু আপনি যখন পরে এটি কল করেন, তখন বাইরের ফাংশনটি ইতিমধ্যে সম্পন্ন হয়েছে। তবুও ভেরিয়েবলটি সেখানে আছে। কীভাবে? এটাই ক্লোজার এবং স্কোপের জাদু। অনেক ডেভেলপার এই ধারণাটি নিয়ে সংগ্রাম করেন, যার ফলে অপ্রত্যাশিত ভেরিয়েবল মান বা মেমরি লিকের মতো বাগ তৈরি হয়। এই নিবন্ধে, আমরা ব্যবহারিক উদাহরণসহ সহজ ভাষায় JavaScript ক্লোজার এবং স্কোপ ব্যাখ্যা করব।
JavaScript-এ স্কোপ কী?
স্কোপ নির্ধারণ করে যে আপনার কোডে ভেরিয়েবলগুলি কোথায় অ্যাক্সেসযোগ্য। JavaScript-এ তিনটি প্রধান ধরনের স্কোপ রয়েছে:
- গ্লোবাল স্কোপ: কোনো ফাংশন বা ব্লকের বাইরে ঘোষিত ভেরিয়েবলগুলি বিশ্বব্যাপী অ্যাক্সেসযোগ্য।
- ফাংশন স্কোপ: একটি ফাংশনের ভিতরে ঘোষিত ভেরিয়েবলগুলি শুধুমাত্র সেই ফাংশনের ভিতরে অ্যাক্সেসযোগ্য।
- ব্লক স্কোপ: একটি ব্লক
{}এর ভিতরেletএবংconstদিয়ে ঘোষিত ভেরিয়েবলগুলি শুধুমাত্র সেই ব্লকের ভিতরে অ্যাক্সেসযোগ্য।
এখানে একটি দ্রুত উদাহরণ:
let globalVar = 'I am global';
function myFunc() {
let functionVar = 'I am in function scope';
if (true) {
let blockVar = 'I am in block scope';
console.log(globalVar); // accessible
console.log(functionVar); // accessible
console.log(blockVar); // accessible
}
console.log(blockVar); // ReferenceError: blockVar is not defined
}
myFunc();
console.log(functionVar); // ReferenceError: functionVar is not defined
স্কোপ বোঝা গুরুত্বপূর্ণ কারণ এটি ভেরিয়েবল সংঘর্ষ প্রতিরোধ করে এবং মেমরি পরিচালনা করতে সহায়তা করে।
লেক্সিক্যাল স্কোপিং: ক্লোজারের ভিত্তি
JavaScript লেক্সিক্যাল স্কোপিং ব্যবহার করে, যার অর্থ একটি ভেরিয়েবলের স্কোপ সোর্স কোডে তার অবস্থান দ্বারা নির্ধারিত হয়। ভেতরের ফাংশনগুলি তাদের বাইরের (আবদ্ধ) স্কোপের ভেরিয়েবলগুলিতে অ্যাক্সেস পায়। এটিকে স্ট্যাটিক স্কোপিংও বলা হয়।
এটি বিবেচনা করুন:
function outer() {
let outerVar = 'outer';
function inner() {
console.log(outerVar); // 'outer'
}
inner();
}
outer();
inner ফাংশনটি outerVar অ্যাক্সেস করতে পারে কারণ এটি লেক্সিক্যালভাবে outer এর ভিতরে। এটি ডাইনামিক নয়; এটি ফাংশন কীভাবে কল করা হয় তার উপর নির্ভর করে না।
ক্লোজার কী?
একটি ক্লোজার হলো এমন একটি ফাংশন যা তার লেক্সিক্যাল স্কোপ মনে রাখে এমনকি যখন ফাংশনটি সেই স্কোপের বাইরে এক্সিকিউট করা হয়। অন্য কথায়, একটি ক্লোজার আপনাকে একটি ভেতরের ফাংশন থেকে একটি বাইরের ফাংশনের স্কোপে অ্যাক্সেস দেয়। প্রতিবার একটি ফাংশন তৈরি হলে, ফাংশন তৈরির সময়েই ক্লোজার তৈরি হয়।
উদাহরণ:
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
এখানে, makeCounter একটি ভেতরের ফাংশন রিটার্ন করে যা count বাড়ায়। makeCounter এক্সিকিউশন শেষ করার পরেও, রিটার্ন করা ফাংশনের এখনও count এ অ্যাক্সেস আছে। এটাই একটি ক্লোজার।
ক্লোজার কীভাবে ভেতরে কাজ করে
যখন একটি ফাংশন তৈরি হয়, তখন এটি তার লেক্সিক্যাল এনভায়রনমেন্টের (স্কোপ চেইন) একটি রেফারেন্স সংরক্ষণ করে। যখন ফাংশনটি আহ্বান করা হয়, তখন এটি ভেরিয়েবল সমাধান করতে সেই এনভায়রনমেন্ট ব্যবহার করে। ক্লোজার যতদিন থাকে, এনভায়রনমেন্টটি ততদিন জীবিত থাকে।
ক্লোজারের ব্যবহারিক ব্যবহার
ক্লোজার শুধু তাত্ত্বিক নয়; এগুলি JavaScript-এ সর্বত্র ব্যবহৃত হয়।
1. ডেটা প্রাইভেসি (মডিউল প্যাটার্ন)
ES6 মডিউলের আগে, প্রাইভেট ভেরিয়েবল তৈরি করতে ক্লোজার ব্যবহার করা হত:
const counterModule = (function() {
let count = 0;
return {
increment: function() { count++; },
getCount: function() { return count; }
};
})();
counterModule.increment();
console.log(counterModule.getCount()); // 1
console.log(counterModule.count); // undefined
এখানে, count প্রাইভেট এবং শুধুমাত্র রিটার্ন করা মেথডের মাধ্যমে অ্যাক্সেসযোগ্য।
2. ইভেন্ট হ্যান্ডলার এবং কলব্যাক
বাইরের স্কোপ থেকে ভেরিয়েবল অ্যাক্সেস করতে ইভেন্ট হ্যান্ডলারগুলিতে ক্লোজার সাধারণত ব্যবহৃত হয়:
function setupButton() {
let clickCount = 0;
document.getElementById('myButton').addEventListener('click', function() {
clickCount++;
console.log(`Button clicked ${clickCount} times`);
});
}
ইভেন্ট হ্যান্ডলার ক্লোজার clickCount মনে রাখে।
3. ফাংশন ফ্যাক্টরি
আপনি পূর্বনির্ধারিত আর্গুমেন্ট দিয়ে ফাংশন তৈরি করতে পারেন:
function multiplyBy(factor) {
return function(number) {
return number * factor;
};
}
const double = multiplyBy(2);
console.log(double(5)); // 10
সাধারণ সমস্যা এবং কীভাবে এড়ানো যায়
বোঝা না গেলে ক্লোজার অপ্রত্যাশিত আচরণ করতে পারে।
লুপ ভেরিয়েবল ক্যাপচার
লুপে var ব্যবহার করলে একটি একক শেয়ার্ড বাইন্ডিং তৈরি হয়:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // prints 3, 3, 3
}, 100);
}
সমস্ত কলব্যাক একই i শেয়ার করে। সমাধান করতে, let (ব্লক স্কোপ) বা একটি IIFE ব্যবহার করুন:
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // prints 0, 1, 2
}, 100);
}
মেমরি লিক
ক্লোজার ভেরিয়েবলগুলিকে জীবিত রাখে। যদি একটি ক্লোজার একটি দীর্ঘজীবী অবজেক্টের (যেমন একটি DOM এলিমেন্ট) সাথে সংযুক্ত থাকে, তবে এটি গারবেজ কালেকশন প্রতিরোধ করতে পারে। আর প্রয়োজন না হলে সর্বদা ইভেন্ট লিসেনার সরান।
স্কোপ চেইন এবং ভেরিয়েবল রেজোলিউশন
যখন আপনি একটি ভেরিয়েবল অ্যাক্সেস করেন, JavaScript স্কোপ চেইন দেখে: প্রথমে বর্তমান স্কোপ, তারপর বাইরের স্কোপ, গ্লোবাল স্কোপ পর্যন্ত। যদি না পাওয়া যায়, একটি ReferenceError নিক্ষেপ করা হয়।
উদাহরণ:
let a = 'global';
function outer() {
let b = 'outer';
function inner() {
let c = 'inner';
console.log(a, b, c); // all accessible
}
inner();
}
outer();
inner এর জন্য স্কোপ চেইন হলো: inner -> outer -> global।
তুলনা: var, let, এবং const
| কীওয়ার্ড | স্কোপ | হোস্টিং | পুনরায় অ্যাসাইনযোগ্য |
|---|---|---|---|
| var | ফাংশন | হ্যাঁ (undefined-এ ইনিশিয়ালাইজড) | হ্যাঁ |
| let | ব্লক | হ্যাঁ (কিন্তু ইনিশিয়ালাইজড নয়, TDZ) | হ্যাঁ |
| const | ব্লক | হ্যাঁ (কিন্তু ইনিশিয়ালাইজড নয়, TDZ) | না |
এই পার্থক্যগুলি বোঝা স্কোপ-সম্পর্কিত বাগ এড়ানোর মূল চাবিকাঠি।
FAQ
JavaScript-এ একটি ক্লোজার কী?
একটি ক্লোজার হলো এমন একটি ফাংশন যা তার লেক্সিক্যাল স্কোপে অ্যাক্সেস ধরে রাখে এমনকি সেই স্কোপের বাইরে এক্সিকিউট করা হলেও। এটি একটি ফাংশনকে "মনে রাখতে" দেয় যে এটি কোথায় সংজ্ঞায়িত হয়েছিল সেখান থেকে ভেরিয়েবলগুলি।
ক্লোজার কেন গুরুত্বপূর্ণ?
ক্লোজার ডেটা প্রাইভেসি, ফাংশন ফ্যাক্টরি এবং ইভেন্ট হ্যান্ডলার সক্ষম করে যা স্টেট বজায় রাখে। এগুলি অনেক JavaScript প্যাটার্নের জন্য মৌলিক।
ক্লোজার-সম্পর্কিত বাগ এড়াতে আমি কীভাবে পারি?
ব্লক স্কোপিংয়ের জন্য let এবং const ব্যবহার করুন, লুপ সম্পর্কে সচেতন থাকুন এবং মেমরি লিক প্রতিরোধ করতে ইভেন্ট লিসেনার পরিষ্কার করুন।
আপনার বোঝাপড়া পরীক্ষা করতে প্রস্তুত? কোড স্নিপেট নিয়ে পরীক্ষা করতে এবং ক্লোজার কীভাবে রিয়েল-টাইমে কাজ করে দেখতে আমাদের JSON Formatter ব্যবহার করুন।