Hoisting-এর মরণ কামড়
বড় বড় বিল্ডিং বানানোর সময় বিশাল বিশাল ক্রেনে করে ইট, সিমেন্ট ও বালু ওপরে উঠানো হয় কাজ করার জন্য। একইভাবে JavaScript-এ কাজের সুবিধার জন্য ভেরিয়েবল ও ফাংশনের নাম (ডিক্লারেশন) ওপরে তোলা হয়। যেন পুরো কোডে এগুলো যেখানে যেখানে দরকার, ইউজ করতে পারে।
নিচে sayHello নাম একটা ফাংশনটি ডিক্লেয়ার করছি। কিন্তু সেটা ডিক্লেয়ার করার আগেই কল করে ফেলছি, তবুও এটি কাজ করবে। কারণ, JavaScript প্রথমেই ফাংশনের ডিক্লারেশনকে ওপরে তুলে নিয়ে যায়। যাতে ডিক্লেয়ার করার আগেই যদি কখনো দরকার হয়, তাহলে ফাংশনটি ইউজ করা যায়। আর ডিক্লেয়ার করার পরে তো এমনি এমনি কাজ করবেই।
sayHello();
function sayHello() {
console.log("Hello, world!");
}
Output: Hello, world!ফাংশন ডিক্লারেশনকে ভিতরে ভিতরে ওপরে তুলে নেয়ার এই প্রসেসকে hoisting বলে। এই hoisting একটা কঠিন শব্দ। এইটার মানে হচ্ছে উত্তোলন করা, ওপরে উঠানো।
এইটুক পর্যন্ত hoisting ইজি আর সিম্পল আছে।
তবে let বা const দিয়ে ভেরিয়েবল ডিক্লেয়ার করলে তলে তলে সেগুলাকে hoisting করা হলেও ভ্যালু সেট করা হয় না (এইটা শুনতে বা চিন্তা করতে একটু ভেজাইল্লা লাগে)। তবে সিম্পলভাবে চিন্তা করতে পারস, let বা const দিয়ে ভেরিয়েবল ডিক্লেয়ার করলে সেটা ডিক্লেয়ারের আগে ইউজ করা যাবে না। এরর দিবে।
let আর const দিয়ে ডিক্লেয়ার করা ভেরিয়েবলগুলো hoist করে একটা জায়গায় রাখে। এই জায়গার নাম Temporal Dead Zone (TDZ)। মানে সাময়িক মৃত্যুর কূপ বা মরণের এলাকা। এই জোনে থাকলে ভেরিয়েবল ইউজ করা যাবে না, পাবেও না; বরং ইউজ করতে চাইলে ReferenceError দিবে। তবে যেখানে let বা const-কে ডিক্লেয়ার করা আছে, তার লাইনে গেলে তখন সে ভেরিয়েবলগুলাকে ইনিশিয়ালাইজ করে ফেলে। অর্থাৎ তাদের মান সেট করে ফেলে।
সেজন্য let আর const দিয়ে ডিক্লেয়ার করা ভেরিয়েবল যেখানে ডিক্লেয়ার করা হইছে, তার আগে ইউজ করা যায় না ( যদিও ভিতরে ভিতরে hoisting ঠিকই হয়)। তবে ডিক্লেয়ার করার পরে ঠিকই ইউজ করা যায়।
console.log(myLet);
console.log(myConst);
let myLet = 20;
const myConst = 30;
Output:
ReferenceError: Cannot access 'myLet' before initialization
ReferenceError: Cannot access 'myConst' before initializationশুধু নরমাল ভেরিয়েবল না। তুই যদি ফাংশন এক্সপ্রেশন দিয়ে একটা ফাংশন লিখছ, সেটার বামপাশে কিন্তু একটা ভেরিয়েবলই। তাই এইটাও let আর const-এর মতো সেইম কেইস। তলে তলে hoisting কাজ করলেও মান সেট হয় না। তাই যেখানে কোড লেখা হয়েছে, তার ওপরে কাজ করবে না। এরর দিবে।
sayHello();
const sayHello = function() {
console.log("Hello!");
};
Output: Uncaught ReferenceError: Cannot access 'sayHello' before initializationফাংশন এক্সপ্রেশনের মতো করে অ্যারো ফাংশনও সেইম কেইস। এইটাও সিম্পল let আর const-এর মতো। সেইম কারণে ডিক্লেয়ারের আগে সেটাকে কল করে ফেললে এরর দিবে।
console.log(greet);
const greet = () => {
console.log("Hello!");
};
Output: Uncaught ReferenceError: Cannot access 'greet' before initializationপুরান আমলের var দিয়ে ভেরিয়েবল ডিক্লেয়ার করলে আবার আরেকটু ডিফারেন্ট কাহিনি। var-দিয়ে ডিক্লেয়ার করা ভেরিয়েবলগুলার নামটা hoist করে কিন্তু মানটা নেয় না। অর্থাৎ var দিয়ে ডিক্লেয়ার করা ভেরিয়েবলকে hositing করে ইনিশিয়ালাইজ করে ফেলে। কিন্তু কোনো মান সেট করে না। আর কোনো মান সেট না করার কারণে ডিফল্ট মান হিসেবে undefined হয়ে যায়।
সেজন্য var দিয়ে ডিক্লেয়ার করা ভেরিয়েবলগুলার মান সেট হওয়ার আগ পর্যন্ত ইউজ করা যাবে। তবে মান পাওয়া যাবে না। মান হিসেবে undefined পাওয়া যাবে। আর ডিক্লেয়ার করার পর ঠিকই মান পাওয়া যাবে।
console.log(myVar);
var myVar = 10;
console.log(myVar);
Output:
undefined
10Hoisting-এ একটা ভেজাইল্লা টপিক। এইটার ভিতরে আরও অনেক অনেক জিনিস আছে। আমি জাস্ট হালকার ওপরে ঝাপসা করে কয়েকটা জিনিস বলেছি।
Practice:
- একটা ভেরিয়েবল ডিক্লেয়ার কর, যেটার মধ্যে কমেন্টের সংখ্যা থাকবে। এখন এই ভেরিয়েবলটাকে ডিক্লেয়ার করার আগের লাইনে এইটার মান এক বাড়ানোর চেষ্টা কর। দেখ কী হয়।
- const দিয়ে views নামে একটা ভেরিয়েবল ডিক্লেয়ার কর। আর ডিক্লেয়ার করার আগের লাইনে এই ভেরিয়েবলকে 2 দিয়ে ভাগ কর। তাহলে ভাগফল কত পাবি?
- Temporal Dead Zone (TDZ) কাকে বলে এবং এটি কেন গুরুত্বপূর্ণ?
- function expression দিয়ে লেখা ফাংশনকে hoisting করলে কেন initialization-এর আগে কল করা যায় না?
- var দিয়ে ডিক্লেয়ার করা ভেরিয়েবলের hoisting behavior কেমন? উদাহরণসহ ব্যাখ্যা কর।
- let এবং var-এর hoisting behavior একই?
- দুইটা সংখ্যার মধ্যে বড় সংখ্যা কোনটা, সেটা বের করার একটা ফাংশন লিখে ফেল। তারপর এই ফাংশন ডিক্লেয়ার করার আগেই সেই ফাংশনকে কল করে ফেল 87 আর 12 দিয়ে। তারপর রিটার্ন যেটা পাবি, সেটাকে কনসোল লগ করে ফেল। যেখানে কনসোল লগ করছস, সেখানে কমেন্ট করে লিখে ফেল, কীভাবে ফাংশন ডিক্লেয়ার করার আগেই সেই ফাংশনকে ইউজ করতে পারলি।