জাভাস্ক্রিপ্ট ভাষার সবচেয়ে বড় বাজওয়ার্ড (buzzword) একটি হলো ক্লোজার (closure)। FAANG কোম্পানিগুলোর জব ইন্টারভিউতে এটিই بارবার জিজ্ঞাসা করা হয়। এই আর্টিকেলে স্কোপ এবং ক্লোজার নিয়ে আলোচনা করা হবে, সহজ উদাহরণের মাধ্যমে কনসেপ্টগুলো বোঝানো হবে এবং শেষে একটি বড় টেক কোম্পানির ইন্টারভিউ প্রশ্নের নমুনা দেখানো হবে।
স্কোপ (Scope)
কেউ আপনাকে বলে কোনো কিছু একটি প্রজেক্টের 'স্কোপ'-এ আছে বা নাই, তার মানে কী?
আমি পেরিস্কোপ বা টেলিস্কোপ ভাবি। এই যন্ত্রগুলো লেন্সের আওতায় যা যা দেখায় সেটাই 'ইন স্কোপ' (in scope)। লেন্সের বাইরে যা আছে সেটি 'আউট অফ স্কোপ'। জাভাস্ক্রিপ্টে তিনটি গুরুত্বপূর্ণ স্কোপ রয়েছে: লোকাল (Local), গ্লোবাল (Global) এবং লেক্সিক্যাল (Lexical)।
লোকাল স্কোপ (Local Scope)
লোকাল স্কোপ তিনটির মধ্যে সবচেয়ে ছোট। একটি ফাংশন ডিক্লেয়ার করলে তার ক숙্লি ব্রেস {} এর ভিতরের সব কিছু সেই ফাংশনের লোকাল। জাভাস্ক্রিপ্ট ইঞ্জিন ফাংশন পড়লে ভেরিয়েবল ডিক্লেয়ার করে, ফাংশন শেষ হলে ভেরিয়েবলগুলো ডিস্ট্রয় করে।
function greeting() {
var websiteName = 'Career Karma';
return `Hello ${websiteName}`;
}
console.log(greeting()); // Hello Career Karma
console.log(websiteName); // ReferenceError: websiteName is not defined
ফাংশনের বাইরে থেকে ভেরিয়েবল অ্যাক্সেস করা যায় না কারণ ফাংশন শেষ হলে ভেরিয়েবলগুলো নষ্ট হয়ে যায়।
গ্লোবাল স্কোপ (Global Scope)
ফাংশনের বাইরে ডিক্লেয়ার করা ভেরিয়েবলগুলো গ্লোবাল স্কোপে থাকে। সকল ফাংশন, স্ক্রিপ্ট এবং মেথড এগুলো অ্যাক্সেস করতে পারে।
let counter = 0; // গ্লোবাল
const add = () => {
let counter = 0; // লোকাল
counter += 1;
return counter;
}
add(); add(); add();
console.log(counter); // 0 (গ্লোবাল counter অপরিবর্তিত)
ফাংশন প্রতিবার কল হলে লোকাল counter নতুন করে ০ থেকে শুরু হয়। গ্লোবাল counter কখনো পরিবর্তন হয় না কারণ ফাংশন নিজের স্কোপে ভেরিয়েবল পেয়ে গেলে গ্লোবালে খোঁজা বন্ধ করে দেয়।
লেক্সিক্যাল স্কোপ (Lexical Scope)
লেক্সিক্যাল স্কোপ হলো জাভাস্ক্রিপ্টের মৌলিক কনসেপ্ট: একটি ফাংশন বা ভেরিয়েবল কোথায় ডিক্লেয়ার করা হয়েছে সেটি নির্ধারণ করে যে কে সেটি অ্যাক্সেস করতে পারবে। নেস্টেড (nested) ফাংশনগুলোর মত রাশিয়ান ম্যাট্রയস্কা (matryoshka) গুঁড়িয়ের মতো: বড় গুঁড়ি ছোট গুঁড়ির কন্টেন্ট জানে না, কিন্তু ছোট গুঁড়ি বড় গুঁড়ির ভেরিয়েবল জানে।
const init = () => {
const var1 = 'Career'; // আউটার স্কোপ
const second = () => {
const var2 = 'Karma'; // ইন্নার স্কোপ
console.log(var1); // Career
console.log(var2); // Karma
return var1 + " " + var2;
};
return second();
};
init();
দুটি নিয়ম: ১) আউটার স্কোপ ইন্নার স্কোপ দেখে না। ২) ইন্নার স্কোপ আউটার স্কোপের ভেরিয়েবল অ্যাক্সেস করতে পারে। এটি একমুখী সম্পর্ক।
ক্লোজার (Closure)
ক্লোজার এবং লেক্সিক্যাল স্কোপের ডেফিনিশন মিলتی জুল্টি, পার্থক্য হলো ক্লোজার হলো হাইয়ার অর্ডার ফাংশন (Higher Order Function) - অর্থাৎ এটি একটি ফাংশন রিটার্ন করে অথবা ফাংশন প্যারামিটার হিসেবে নেয়। ক্লোজার হলো এমন একটি ফাংশন যা তার লেক্সিক্যাল স্কোপ অ্যাক্সেস করতে পারে, এমনকি সেই ফাংশনটি পরবর্তীতে কল করা হলে।
function greeting() {
const userName = "CrrKrma1952";
function welcomeGreeting() {
console.log("Hello, " + userName);
return "Hello, " + userName;
}
return welcomeGreeting; // ফাংশন রিটার্ন করলো → HOF
}
const greetUser = greeting();
greetUser(); // Hello, CrrKrma1952
এখানে greeting() ফাংশনটি welcomeGreeting ফাংশনটি রিটার্ন করে। greetUser কল করলে welcomeGreeting এক্সিকিউট হয় এবং প্যারেন্ট স্কোপের userName অ্যাক্সেস করতে পারে, mặc dù greeting() এর এক্সিকিউশন কনটেক্সট কেবলমাত্র শেষ হয়ে গেছে। এটি হলো ক্লোজার।