Hoisting
一般情況
// example 1
console.log(a) // ReferenceError: a is not defined
// 完全沒宣告 > 合理
// example 2
console.log(a) // undefined -> 下面的變數提升上來了
var a
// 想像成
var a
console.log(a)
// example 3
console.log(a) // undefined -> 但有賦值,值並不會提升
var a = 5
// 想像成
var a
console.log(a)
a = 5
function 傳入參數的 hoisting
function test(v){
console.log(v) // 8
var v = 5
}
test(8)
//可以想像成
function test(v){
var v = 8
var v
console.log(v) // 所以輸出8
v = 5
}
test(8)
function 的 hoisting 優先權
console.log(a) // function a 因為 function 優先於 變數
var a = 5
function a(){}
如果沒有 hoisting
變數一定要先宣告才能用 > ok
一定要先宣告函式才能用 > not ok
沒有辦法 function 互相呼叫
深度了解
文章連結:TechBridge 技術共筆部落格 - hoisting
剖析hoisting
函數執行時,會產生所謂的EC(Execution context)環境,這環境會儲存這個 function 內所需要的所有資訊,這函數需要什麼就去 EX 拿就對了。
每個 EC 有相對應的變數空間物件稱 VO(variable object),在內宣告的變數跟函式都會被加進去,如果有參數,那參數也會加到 VO 內
對於 js 而言,var a = 10
首先分成左半邊 var a > VO 去新增一個屬性叫做 a,如果沒有這個屬性,就讓它 undefined。
再來看到右半邊 a = 10 > 去 VO 裡面找到 a 這個屬性,找到後設定為 10
啊如果找不到,就利用 scope chain 向上找,如果找不到最後就拋錯
// scope chain
const v = 1 // let or var > same
function test(a){
console.log(v) // 1
let b = 2
console.log(b) // 2
}
test(3)
// example 1 > VO的作法
function test(a,b,c){}
test (10)
// VO 環境(這邊會發現參數為第一優先順序)
{
a:10,
b:undefined,
c:undefined
}
// example 2 > VO的權重
function test(a){
function a(){}
}
test(10)
// VO 環境
{
a: function a
}
如果在VO 內,已經有這個屬性了,那值不會被覆寫掉
// 如果在 VO 內,已經有這個屬性了,那值不會被改變
function test (a){
console.log(a)
var a = 3
}
test(4)
// VO 環境
{
a = 4 // 傳參數進去, a就是等於 4了,就算 function 裡有也不會被改變
}
// function 角度
function test(a){
var a = 4 // 這行是想像
console.log(a) // 所以這邊對於 函式來說看到是這樣子
var a = 3
}
// 所以在這裡面第一個 10 沒問題,而二個 輸出 3 是因為又在宣告一次,故輸出3
function test(a){
console.log(a) //10
var a = 3
console.log(a) // 3
}
test(10)
Temporal Dead Zone
所謂的「暫時性死區」,就是「提升之後」至「賦值之前」這段期間
for const
& let
在 let & const 這兩個部分,也存在著 hoisting,只是結果與 var 不同
如果是 var
> 會報 undefined
如果是 let
or const
> 會報 錯誤
function test() {
var a = 1; // c 的 TDZ 開始
var b = 2;
console.log(c)
// 如果是 const or let 就會報錯
// 如果是 var 就會 undefined
if (a > 1) {
console.log(a)
}
const c = 10 // c 的 TDZ 結束
}
test()
而TDZ 是一種時間的概念
在執行時,如果這個變數還沒有被賦值,就是會報錯(const
& let
)
而如果是 var
就是 undefined
function test() {
yo() // c 的 TDZ 開始
let c = 10 // c 的 TDZ 結束
function yo(){
console.log(c) //這邊會報錯,因為在執行當下 c 還未被賦值
}
}
test()
Last updated
Was this helpful?