Hoist
Hoisting in Modern JavaScript - let, const ,and var
Hoisting ဆိုတာ JavaScript program တစ်ခု compile လုပ်နေစဥ်အတွင်း JavaScript engine က function declaration နဲ့ variable declaration တို့ကို ဘယ်လိုအလုပ်လုပ်တယ်ကို ဆိုလိုခြင်းဖြစ်ပါတယ်။ compiling လုပ်ခြင်း အဆင့် ဆင့် အတွင်းမှာ ကျနော် တို့ ရဲ့ program လေး execution မဖြစ်ခင်အချိန်လေးအတွင်းမှာ function declaration နဲ့ variable declaration တို့ကို hoisting လုပ်ပါတယ်။ တစ်နည်းအားဖြင့် သူတို့ကို scan လိုက်ပါတယ်။ ပြီးတော့ အဲ့ဒီ functions နဲ့ variables တွေအကုန်လုံးကို JavaScript data structure လို့ခေါ်တဲ့ Lexical Environment ထဲကို ထည့်လိုက်ပါတယ်။ ဒါကြောင့် variables တွေ function တွေကို တကယ် source code ထဲမှာ မရေးရသေးဘဲနဲ့တောင် သုံးလို့ရနေခြင်း ဖြစ်ပါတယ်။
ဒါဆို ဒီမှာ Lexical Environment ကဘာလဲ မေးစရာရှိပါတယ်။ Lexical Environment ဆိုတာ identifier-variable mapping ကို လုပ်ဆောင်တဲ့ data structure တစ်ခုပါ။ ဒီမှာ identifier ဆိုတာ variables တွေ functions တွေရဲ့ names တွေကို ဆိုလိုတာပါ။ နောက် variable ဆိုတာကတော့ တကယ့် object တွေ function object တွေရဲ့ reference ကိုဆိုလိုတာပါ။
LexicalEnvironment = {
Identifier: ,
Identifier:
}
ဒါကတော့ lexical Environment ရဲ့ structure ပုံစံပါ။ အတိုချုပ်ပြောရရင် lexical environment ဆိုတာ js program တွေ execution လုပ်တဲ့အခါ variables တွေနဲ့ function တွေရှိတဲ့နေရာပါ။ နောက်သင်ခန်းစာမှာ Lexical Environment အကြောင်းကို သေခြာရှင်းပြပါ့မယ်။
Hoisting Function Declaration
Function declaration မှာဆိုရင် Hoisting က ဒီလိုလုပ်ပါတယ်။
helloWorld(); // prints 'Hello World!' to the console
function helloWorld(){
console.log('Hello World!');
}
ဒီမှာ ဆို helloWorld() ဆိုတဲ့ function အကြောင်းကို မရေးရသေးဘဲနဲ့ အရင်ဆုံး ခေါ်သုံးထားသော်လည်း အလုပ်လုပ်ပါတယ်။ အဲ့ဒီလို အလုပ်လုပ်ခြင်းက JavaScript Hoisting ပဲဖြစ်ပါတယ်။ သူကဘယ်လိုလုပ်လဲဆိုရင် ကျနော်တို့အပေါ်မှာ ပြောခဲ့တဲ့အတိုင်း compile အဆင့်မှာ အရင်ဆုံး helloWorld()ဆိုတဲ့ function declaration ကို အရင်ဆုံး memory ထဲထည့်လိုက်ပါတယ်။ ဒါကြောင့် memory ထဲမှာ ရှိနှင့်တာကြောင့် helloWorld() လို့အရင်ခေါ်လည်း အလုပ်လုပ်ခြင်းဖြစ်ပါတယ်။
ဒီprogram လေးကို Lexical Environment ထဲမှာ ဒီလိုလုပ်ပါတယ်။
lexicalEnvironment = {
helloWorld: < func >
}
ဒီမှာဆိုရင် JavaScript engine က helloWorld() ဆိုတဲ့ function call တစ်ခုကို တွေ့တဲ့အခါ အရင်ဆုံး သူက lexical environment ကိုသွားကြည့်ပါတယ်။ အဲ့ဒီထဲမှာ သူတွေ့တဲ့ function ရှိမှသာ အဲ့ဒီ function call ကို အလုပ်လုပ်ပါတယ်။
Hoisting Function Expressions
JavaScript မှာ function declarations ကိုပဲ hoisting လုပ်ပါတယ်။ function expressions ကို hoisting မလုပ်ပါဘူး။
helloWorld(); // TypeError: helloWorld is not a function
var helloWorld = function(){
console.log('Hello World!');
}
ဒီမှာဆိုရင် typeError ဖြစ်ပါလိမ့်မယ်။ ဘာကြောင့်လဲဆိုတော့ JavaScript က declarations တွေကိုပဲ Hoist လုပ်ပါတယ်။ initialization(assignments) တွေကို Hoist မလုပ်တဲ့အတွက်ကြောင့် helloWord က function မဟုတ်ဘဲနဲ့ variable တစ်ခုအနေနဲ့ပဲရှိနေပါတယ်။ ဘာကြောင့်လဲဆိုတော့ var keyword နဲ့ကြေညာထားတဲ့ variable ဖြစ်နေလို့လည်းပါပါတယ်။ ဒါကြောင့် JavaScript engine က var variable ကို hoisting လုပ်တဲ့အခါမှာ undefined အဖြစ်သတ်မှတ်ထားခြင်းဖြစ်ပါတယ်။
ဒီလိုဆိုရင် code ကအလုပ်လုပ်ပါလိမ့်မယ်။
var helloWorld = function(){
console.log('Hello World!'); prints 'Hello World!'
}
helloWorld();
ဘာကြေင့်လည်း ဆိုတော့ helloWorld variable ကို အရင် initialized လုပ်ထားပါတယ်။ ဒါကြောင့် compling အဆင့်မှာကတည်းက lexical environment ထဲမှာ helloWord ဆိုတဲ့ variable declaration ကို store လုပ်ထားပါတယ်။ ဒါကြောင့် JavaScript engine က helloWorld() function ကို executed လုပ်ဖို့ lexical environment ထဲသွားကြည့်တဲ့အခါ helloWorld ကို declaration နဲ့အတူ initialized(assigned value) လုပ်ထားတာ တွေ့တာကြောင့် function execution ဖြစ်သွားပါတယ်။
Hoisting var variables
console.log(a); // outputs ‘undefined’
var a = 3;
ဒီမှာဆိုရင် ကျနော်တို့ မျှော်လင့်ထားတာ output 3 ကိုပါ။ ဒါပေမဲ့ undefined ဆိုပြီးထွက်ပါတယ်။ ဘာကြောင့်လဲ? ကျနော် တို့အပေါ်မှာပြောခဲ့သလိုပဲ JavaScript က declarations ကို ပဲ hoist လုပ်ပါတယ်။ initializations ကို hosit မလုပ်ပါဘူး။ Compile လုပ်နေစဥ်အချိန်အတွင်းမှာ JavaScript က function နဲ့ variable declarations တွေကိုပဲ သိမ်းထားပါတယ်၊ သူတို့ရဲ့ assignments(value) တွေကို မသိမ်းပါဘူး။ ဒါဆိုရင် ဘာကြောင့် ‘undefined’ ဖြစ်နေတာလဲ? js program ကို compile လုပ်နေစဥ်အတောအတွင်းမှာ JavaScript engine က var variable declaration ကိုတွေ့တဲအခါ အဲ့ဒီ var variable ကို lexical environment ထဲမှာ var variable ရဲ့ valueကို undefined အဖြစ်အရင်သိမ်းထားပါတယ်။ ဒါကို lexical environment ထဲမှာပြမယ်ဆို ဒီလိုပါ။
lexicalEnvironment = {
a: undefined
}
ဒါကြောင့် ကျနော်တို့က 3 ရမယ့်အစား undefined ကိုရတာပါ။ program တစ်ခုလုံး compile လုပ် ပြီးလို့ execution ဖြစ်သွားတဲ့အချိန်မှသာ var variable ထဲကို assignment (value) ကိုတွေ့ခဲ့ရင် undefined ကို ကျနော်တို့ assign လုပ်တဲ့ value နဲ့ ပြန် change ပါတယ်။ ဒါကြောင့် JavaScript engine က variable ကို assignment လုပ်ထားတဲ့ code line ကို ရောက်မှသာ variable ရဲ့ value ကို lexical environment အတွင်းမှာ သွားပြီး updated ပြန်လုပ်လိုက်ပါ့တယ်။ ဒါကြောင့် lexical environment အတွင်းမှာ ဒီလိုဖြစ်နေတာ တွေ့ရပါတယ်။
lexicalEnvironment = {
a: 3
}
Hoisting let and const variables
variable ကို let or const နဲ့ ဆိုရင် hoisting က ဒီလိုလုပ်ပါတယ်။
console.log(a);
let a = 3;
Output => ReferenceError: a is not defined
ဒီမှာဆိုရင် output က ReferenceError ဖြစ်ပါတယ်။ ဒါဆို let နဲ့ const variables တွေကို hoist မလုပ်ဖူးလား။ အဖြေက ပြောရရင်နည်းနည်းရှုပ်ပါတယ်။ တကယ်တော့ JavaScript engine က declarations( function ,var,const and class) တွေ အကုန်လုံးကို hoist လုပ်ပါတယ်။ ဒါပေမဲ့ var variables ကို ကြတော့ undefined ဆိုပြီး lexical environment ထဲမှာ assign(initialized) လုပ်ထားလိုက်ပြီး let variables နဲ့ const variables တွေကိုကျတော့ uninitialized မလုပ်ဘဲချန်းထာခဲ့ပါတယ်။ ဒါကြောင့် သူတို့ကို assign မလုပ်ခင်(value မထည့်ခင်) ခေါ်သုံးထားတာကို တွေ့တဲ့ အတွက်ကြောင့် reference Error ဖြစ်နေပါတယ်။ သဘောက ကျနော်တို့က variable တစ်ခုကို code ထဲမှာ declaration လုပ်ထားရုံနဲ့ အသုံးပြုလို့မရဘူးလို့ဆိုလိုခြင်းဖြစ်ပါတယ်။ အဲ့ဒီလို ဖြစ်ခြင်းကို “Temporal Dead Zone”( variable တစ်ခုကို creation လုပ်ခြင်းနဲ့ initialization လုပ်ခြင်း ကြားထဲက အချိန်ကို အသုံပြုလို့မရနိုင်ခြင်း) လို့ခေါ်ပါတယ်။ အကယ်၍သာ JavaScript engine က code execution ဖြစ်သွားသည်အထိ let variable နဲ့ const variable က်ုမတွေ့ခဲ့ဖူးဆိုရင် တော့ undefined ကို initialized(value အဖြစ် undefined) လုပ်လိုက်ပါတယ်။ ဒါက const variable အတွက်ပဲလုပ်တာပါ။
နောက်ထပ်ဥပမာ တစ်ခုထပ်ရေးပြပါ့မယ်။
let a;
console.log(a); // outputs undefined
a = 5;
ဒီမှာဆိုရင် Compile လုပ် နေစဥ်အဆင့်အတွင်းမှာ JavaScript engine က variable a ကို အရင်တွေ့ပါတယ်။ ဒါကြောင့် a ကို lexical environment ထဲမှာ သိမ်းထားပါတယ်။ let variable ဖြစ်တဲ့အတွက်ကြောင့် uninitialized ဖြစ်ထားထားပါတယ်။ ဒါကြောင့် compile လုပ်နေစဥ်အတွင်းမှာ lexical environment ကို ဒီလိုတွေ့ရပါလိမ့်မယ်။
lexicalEnvironment = {
a:
}
ဒါကြောင့် ကျနော်တို့ variable ကို declared မလုပ်ရသေးခင် accessလုပ်နေတာဖြစ်တဲ့ အတွက်ကြောင့် JavaScript engine က value ထုတ်ပေးဖို့ကြိုးစာပါတယ်။ အဲဒီလို value ထုတ်ပေးဖို့အတွက် lexical environment ထဲကို သွားကြည့်ပါတယ်။ lexical environment ထဲမှာ မရှိတဲ့အတွက်ကြောင့် refrence error ဖြစ်သွားပါတယ်။ execution လုပ်နေစဥ် အချိန်အတွင်းမှာ JavaScript engine က variable delcaration ကိုတွေ့တာကြောင့် variable ရဲ့ value ကိုမတွေ့တာကြောင့် variable ကို undefined ဆိုပြီး value assign လုပ်လိုက်ပါတယ်။ ဒါကြောင့် ပထဆုံး declaration အကြောင်းကို execution ဖြစ်ပြီးတဲ့နောက်မှာ lexicalEnvironment ထဲမှာ ဒီလိုဖြစ်သွားပါတယ်။
lexicalEnvironment = {
a: undefined
}
ဒါကြောင့်နောက်တစ်ကြောင်းဖြစ်တဲ့ console.log ကို execution ပြီးတဲ့အခါ undefined ကို output ထုတ်လိုက်ပါတယ်။ နောက်ဆုံးကြောင်းဖြစ်တဲ့ value assign ကို execution ပြီးသွားတဲ့အခါ lexicalEnvironment ထဲမှာ a: 5 ဆိုပြီး ဖြစ်သွားပါတယ်။
lexicalEnvironment = {
a: 5
}
ဒီမှာ let နဲ့ const variables တို့ကို ဒီလိုပုံစံနဲ့ reference ယူလို့ရပါတယ်။
function foo () {
console.log(a);
}
let a = 20;
foo(); // 20
ဒီမှာဆိုရင် တော့ output 20 ဆိုပြီးတွေ့ရပါလိမ့်မယ်။ ဒါကို lexical Environment ထဲမှာ အရင်ဆုံး a က uninitialized ဖြစ်ပါတယ်။ ပြီးတော့ JavaScript engine က သူ့ကို execution လုပ်တဲ့အခါ declaration နဲ့ value assigned ကိုတွေ့တဲ့အတွက် a ထဲကို 20 အဖြစ် value assign ပြန် update လုပ်လိုက်ပါတယ်။ ဒါကြောင့် နောက်တစ်ကြောင်းဖြစ်တဲ့ foo() function ကို တွေ့တဲ့ အခါ lexical Environment ထဲကို ပြန်ကြည့်တဲ့အခါ a : 20 ကိုတွေ့တာကြောင့် output 20 ဆိုပြီး execution ဖြစ်သွားပါတယ်။
ဒီလိုဆိုရင်တော့ ReferenceError ဖြစ်ပါလိမ့်မယ်။
function foo() {
console.log(a); // ReferenceError: a is not defined
}
foo(); // This is not valid
let a = 20;
ဒီလိုဆိုရင်တော့ undefined နဲ့ 20 ရပါလိမ့်မယ်။
function foo () {
console.log(a);
}
foo(); // undefined
var a = 20;
foo(); // 20
ဘာကြောင့်လဲဆိုတော့ var variable ဖြစ်နေလို့ပါ။
ဒါဆိုရင်တော့ ကျနော်တို့ဘာကြောင့် ReferenceError တွေ undefined တွေဖြစ်နေတာလဲ ဆိုတာနားလည်းမယ်လို့ထင်ပါတယ်။ ဒါကြောင့် hoisting effect တွေဖြစ်တဲ့ undefined variables တွေ reference error တွေကိုမဖြစ်အောင် variable ကိုတွေကို declare လုပ်တဲ့အခါ တစ်ခါတည်း initialized လုပ်ဖို့ (values assign ထည့်ဖို့) တိုက်တွန်းခြင်ပါတယ်။
No comments:
Post a Comment