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
এরর ই আসবে :)