[JavaScriptWeird]No.58 hoisting 順序

前言

hoisting 有順序? 抱歉我也不知道,不知道的東西就該好好記錄下來~

hoisting 順序問題

前篇了解基礎觀念後,接著要來了解一些之前從來沒有想過的問題。

1
2
3
4
5
6
function test(){  
console.log(a);
var a = 'local';
function a(){}
}
test(); // ƒ a(){}

宣告變數 a 之後,在宣告一個 a 的函式陳述式,結果居然會印出函式。

1
2
3
4
5
6
function test(){  
console.log(a);
function a(){}
var a = 'local';
}
test(); // ƒ a(){}

再將順序調換,仍然印出函式。

代表 hoisting 後的順序,函式的優先權是比變數高的

1
2
3
4
5
6
7
function test(){  
function a(){}
var a;
console.log(a);
a = 'local';
}
test(); // ƒ a(){}

可以把原本的程式碼想像成上面這樣,這邊也有個陷阱。

我們可能會想說:「明明下一行是 var a 可是為什麼印出來的 a 不是 undefined

然而 JavaScript 是這樣的:

  • var 可以重複宣告變數
  • 使用 var 宣告的變數如果已經存在,且新宣告同名的變數又未賦值時,則不會對原本變數造成影響。

這段話的意思用程式碼表達是這樣的:

1
2
3
4
5
6
7
8
9
var a = 10;  
var a;
var a;
console.log(a); // 10;
var a;
var a;
var a;
var a = '安安';
console.log(a); // 安安;

回到原本的例子,就可以明白為何還是印出函式了。

同樣的例子,再度調換程式碼位置

1
2
3
4
5
6
function test(){  
var a = 'local';
console.log(a);
function a(){}
}
test(); // local

如果這邊回答印出函式,那麼代表又中陷阱啦~

根據剛剛的觀念,好好的來排一下順序:

1
2
3
4
5
6
7
function test(){  
function a(){}
var a;
a = 'local'
console.log(a);
}
test(); // local

  • 函式有優先權,先提升
  • 再來是變數,賦值不會提升
  • 同名變數又被重新賦值

所以結果才會是 local

同名函式的 hoisting 優先順序

1
2
3
4
5
6
7
8
9
10
11
function test(){  
console.log(a);
function a(){
console.log(1);
};
function a(){
console.log(2);
};
var a = 'local';
}
test(); // ƒ a(){console.log(2);}

由此可知,同名函式的情況下,很合理的是後面蓋前面

函式有參數的情況下

1
2
3
4
5
function test(a){  
console.log(a);
var a = 456;
}
test(123); // 123

此時相當於

1
2
3
4
5
6
function test(a){  
var a;
console.log(a);
a = 456;
}
test(123); // 123

可知參數 hoisting 的優先權是大於變數的。

接著來測試參數與函式的優先權

1
2
3
4
5
6
7
function test(a){  
console.log(a);
function a(){

}
}
test(123); // ƒ a(){}

可知函式 hoisting 的優先權是大於參數的。

hoisting 優先順序總結

  • 函式 (function) 最優先
  • 參數 (arguments) 其次
  • 變數最後

除了考慮 hoisting 順序以外,也與程式碼的執行順序有關。
所以最後再來個例子,考考自己有沒有懂:

1
2
3
4
5
6
function test(a){  
console.log(a); // 123
var a = 456;
console.log(a); // 456
}
test(123);

========

1
2
3
4
5
6
7
function test(a){  
var a;
console.log(a); // 123
a = 456;
console.log(a); // 456
}
test(123);

心得

這一小節真的是太猛啦,根據前世的記憶(?),奇怪部分對於 hoisting 的補充並沒有這麼多範例,而且我也從來沒想過 hoisting 這邊可以有這麼多陷阱。

真的是非常感謝這一系列影片,覺得自己又更認識 JavaSctipt 一點。

然後,關於 hoisting 還不只這樣哦,還要繼續深~下去。

0%