JavaScript Hoisting - No more confusion!

হোশটিং হচ্ছে জাভাস্ক্রিপ্ট এর স্কোপ কনসেপ্ট এর মতো। স্কোপ হচ্ছে কাকে আমরা কই ডিফাইন করলে কোথায় অ্যাক্সেস করতে পারবো আর হোশটিং হচ্ছে আমরা যে জাভাস্ক্রিপ্ট এর ভেরিয়েবল গুলো ডিফাইন করি তাকে জাভাস্ক্রিপ্ট কিভাবে ডিল করে তারই বর্ণনা।

নিচের কোডটি লক্ষ্য করুনঃ

console.log(a); // output 'reference error'

অর্থাৎ আমরা যদি কোনো ভেরিয়েবল কে না ডিফাইন করে তার আউটপুট দেখতে চাই তাহলে সরাসরি আমরা একটা এরর পাবো এটায় তো স্বাভাবিক।

var a = 'Bangladesh'; console.log(a); // output 'Bangladesh'

এটা তো আমরা জানি যে যদি একটা ভেরিয়েবলকে ডিফাইন করি তারপর তাকে কনসলে লগ করি তখন তার ভ্যালু টা আমরা পাই। কিন্তু কি হবে যদি

console.log(a); var a = 'Bangladesh'; // output 'undefined'

আমরা ভেরিয়েবল কে ডিফাইন করার পূর্বে তাকে অ্যাক্সেস করার ট্রাই করি তখন আমরা একটা এরর পাবো তা হচ্ছে undefined

অর্থাৎ এখানে থেকে হোশটিং এর কনসেপ্ট টা আসে।

var a; // here variable is define a = 'Bangladesh'; // here variable is assigne by value of 'Bangladesh'

এখানে প্রথম যখন একটা জাভাস্ক্রিপ্ট ফাইল রিড হয় তখন কি হয় সকল ভেরিয়েবল ডিফাইন গুলো হোশটিং করে অর্থাৎ উত্তোলন করে/উপরের দিকে উঠায় নেয় এবং একটা মান আসাইন করে তা হচ্ছে undefined তাই এই কোডকে যদি একটু মডিফাই করে লিখি তাইলে বুঝতে সুবিধা হবে।

console.log(a); var a = 'Bangladesh'; // output 'undefined'

মডিফাইড

console.log(a); var a; a = 'Bangladesh'; // output 'undefined'

var a; কে উপরের দিকে নিয়ে যাবে ঠিক এই রকম

var a; console.log(a); a = 'Bangladesh'; // output 'undefined'

ঠিক এইরকম টা হয়ত হয় না কিন্তু বুঝার সুবিধার্থে ধরে নেন। তারপর var a; এর ভ্যালু by default undefined সেট করে দেয় তারপর আমরা তার ভ্যালু কনসলে undefined দেখতে পাই। তারপর গিয়ে তার ভ্যালু সেট হয় Bangladesh. আমরা যদি তারপর আবার কনসোল করি তাহলে

var a; console.log(a); a = 'Bangladesh'; console.log(a); // output 'undefined' // output 'Bangladesh'

এই রকম দেখতে পাবো। এটাই সিম্পিলি হোশটিং বলা যায়। চলুন আর একটু জানা যাক।

Using let

উপরের ব্যবহৃত সকল উদাহরণ গুলো যদি let দিয়ে দেখি তাহলে কি হবে। চলুন-

console.log(a); // output 'reference error' let a = 'Bangladesh'; console.log(a); // output 'Bangladesh'

এই দুইটা সেইম ।

console.log(a); var a = 'Bangladesh'; // output 'undefined' console.log(a); let a = 'Bangladesh'; // output 'reference error'

কনসলে আসা এরর টা দেখেন-

দেখুন var ব্যবহার করলে আসে undefined আর let ব্যবহার করলে আসে real error. হুম একটু ব্যতিক্রম অর্থাৎ var and let একটু ভিন্ন ওয়েতে কাজ করে both ক্ষেত্রেই হোশটিং হচ্ছে।

let এর ক্ষেত্রে আসলে ডিক্লেরশন টা উপরে যায় কিন্তু আনডিফাইন্ড টা সেট হয় যে লাইনে let লেখা হয়েছে ঠিক অই লাইনে আর ভ্যালু টা অ্যাসাইন হয় ঠিক তার পরের লাইনে।

console.log(a); let a; // here a = undefined assign a = 'Bangladesh'; // here a = 'Bangladesh' value assign // কল্পনা করে দেখলে এইরকম হবে তেমন কিছু না।

আমার চিন্তা এবার বুঝতে পারছেন। তাই যেহেতু ভেরিয়েবলই অ্যাসাইন হচ্ছে না আমার মেমোরিতে অ্যালোকেট হচ্ছে না তাই তাকে reference error দেখাচ্ছে।

কিন্তু আমরা যদি এভাবে লিখি

let a; console.log(a); a = 'Bangladesh'; // output - 'undefined' // এখন ভেরিয়েবল var এর মতো কাজ করছে কারন কনসোল এর পূর্বেই a এর মান undefined সেট হয়েছে।

Some complex example

var LANGUAGE = 'Java'; var language = 'JavaScript'; function getLanguage() { if (!language) { var language = LANGUAGE; } return language; } console.log(`I love ${getLanguage()}`); // expected - 'I love JavaScript'

তাহলে এখানে আমরা কি আউটপুট পেতে পারি।

// output - 'I love Java'

এর কারন কি? কারন হলো হোশটিং আর var কারন এত খন যাবত আমরা যা জেনেছি চলুন তা দিয়ে কল্পনা করে দেখার চেষ্টা করি কি হচ্ছে।

var LANGUAGE = 'Java'; var language = 'JavaScript'; function getLanguage() { if (!language) { var language = LANGUAGE; } return language; } console.log(`I love ${getLanguage()}`); // expected - 'I love JavaScript'

দেখুন এখানে var language = LANGUAGE; এটা হোশটিং হয়ে উপরে যাবে কিন্তু আবার ফাংশন কে ছেরে উপরে না কারন এখানে আবার স্কোপ আছে যে if এর উপরে যেতে পারবে সর্বোচ্চ তখন গিয়ে সেখানে সেট হবে var language = LANGUAGE; মানে 'Java' এবং দেখবে !language false তাই আর if এর ভেতরে ঢুকবে না যাবে রিটার্নে এখন ত language এর ভ্যালু চেঞ্জড মানে 'Java' তাই আমরা Java আউটপুট দেখতে পাচ্ছি।

আর যদি let ব্যবহার করি তাহলে আমরা সঠিক আউটপুট দেখতে পাচ্ছি চলুন বর্ননা করা যাক

let LANGUAGE = 'Java'; let language = 'JavaScript'; function getLanguage() { if (!language) { let language = LANGUAGE; } return language; } console.log(`I love ${getLanguage()}`); // expected - 'I love JavaScript' // output - 'I love JavaScript'

দেখুন এখানে let language = LANGUAGE; এটা হোশটিং হয়ে উপরে যাবে কিন্তু আবার if কে ছেরে উপরে যাবে না কারন এখানে আবার let block স্কোপ আছে তাই সে if এর উপরে যেতে পারবে না তখন ভেরিয়েবল আনডিফাইন্ড আসাইন হবে if এর ভিতর সেট হবে । যদি একটু কল্পনা করে দেখার চেষ্টা করি কি হচ্ছে।

let LANGUAGE = 'Java'; let language = 'JavaScript'; function getLanguage() { if (!language) { let language = LANGUAGE; // here language = undefined assing // here language = LANGUAGE value assing } return language; } console.log(`I love ${getLanguage()}`); // expected - 'I love JavaScript' // output - 'I love JavaScript'

let language = LANGUAGE; মানে 'JavaScript' এবং দেখবে !language false কারন ফাংশন স্কোপ এ language এর ভ্যালু নাই কিন্তু তার পেরেন্ট এ তো আছে তাই এটা true তাই আর if এর ভেতরে ঢুকবে না যাবে রিটার্নে এখন ত language এর ভ্যালু পেরেন্ট থেকে আসা মান মানে 'JavaScript' তাই আমরা JavaScript আউটপুট দেখতে পাচ্ছি।

Function Hoisting

জাভাস্ক্রিপ্ট এ faunction ও একই নিয়মে হোশটিং হয়ে থাকে

myFunc(); function myFunc() { var language = 'JavaScript'; console.log(language); } // output - 'JavaScript'

আসলে জাভাস্ক্রিপ্ট এ function ও একটি Object এটা ও মেমোরিতে অ্যালোকেট হয় কারন ফাংশন ও একটা ডেফিনেশন তাই প্রথম এ হোশটিং করে উপরে যায় মেমোরিতে অ্যালোকেট হয় তার পর এটা এক্সোকিউট হয়।

আচ্ছা বলুন ত নিচের কোডের আউটপুট কি হবে

myFunc(); function myFunc() { language = 'JavaScript'; var language; console.log(language); } // output - 'undefined / 'JavaScript'

আসলে এখানে JavaScript ই আসবে কারন কি আমাদের সেন্স এ ত language = 'JavaScript'; যেহেতু var নাই তাই গ্লোবাল এ by default একটা var language; নিবে আর আনডিফাইন্ড সেট করবে ভালো কথা। তারপর ফাংশন বডি তে এসে JavaScript ভ্যালু আসাইন হবে তারপর ত আবার var language; undefined সেট হবার কথা তাই তো কিন্তু না আমরা কি জানি var language; তো function scope তাই এটা ও তো হোশটিং হয়ে উপরে যাবে ফাংশন বডির সবার উপরে তারপর কিন্তু JavaScript ভ্যালু সেট হবে তাই কিন্তু আমরা আউটপুট ঠিকঠাক পাচ্ছি।

কিন্তু আমার যদি জাভাস্ক্রিপ্টকে একটু অন্য ভাবে লিখি

myFunc(); const myFunc = function () { var language = 'JavaScript'; console.log(language); }; // output - check picture

তাহলে কি হলো এখানে আবার ব্যতিক্রম কেনো। কোনোই ব্যতিক্রম না যেহেতু এখানে ফাংশন কে ভেরিয়েবল এ ডিফাইন করা হয়েছে আবার const দিয়ে তাই এখানে কল্পনা করলে এমন হবে

const myFunc; // not allocate here myFunc(); const myFunc = undefined ; myFunc = function () { var language = 'JavaScript'; console.log(language); }; // output - so reference error

Summary

হোশটিং তেমন কিছুই না একটা জাভাস্ক্রিপ্ট ফাইল রিড করার সময় সকল প্রকার ডিফাইন গুলো সবার উপরে হোশটিং/উত্তলন হয় কিন্তু এখানে function var let and const এর তিনটায় কিছু টা পার্থক্য লক্ষ্য করা যায়। var আর function এ যার যার স্কোপ এর সবার উপরে ডিফল্ট ভ্যালু undefined সেট হয় এবং পরবর্তীতে তার ভ্যালু অই লাইনে আসাইন হয়। আর let and const এর ক্ষেত্রে অই লাইনে undefined সেট হয় এবং ভ্যালু আসাইন হয়। আর function কে যদি ভেরিয়েবল let and const দিয়ে ডিক্লেয়ার করা হয় তাহলে অই লাইনে undefined সেট হয়। আর সাধারন function দিয়ে তৈরি করলে গ্লোবালি রেফারেন্স পাই তাই ফাংশন কল হয়। কিন্তু var ব্যবহার করলে আনডিফাইন্ড আশার কথা কিন্তু না। তা কেন নিচে লক্ষ্য করুন।

myFunc(); var myFunc = function () { var language = 'JavaScript'; console.log(language); }; //output - Uncaught TypeError: myFunc is not a function

এখানে undefined আশার কথা কিন্তু এরর আসছে কেন? কারন আমার তো () কল করছি। myFunc এর ভ্যালু undefined তো তা ত আর ফাংশন না তাই তাকে কল করলে ত not a function এরর ই আসবে :)