什麼是Hoisting(提升)?
console.log(b) //b is not defined -> 報錯
//沒有宣告b的情況下,會直接報錯。
console.log(b)
var b = 10 //undefined
//在後面做宣告時沒有報錯?
//是因為宣告被Hoisting(提升),但賦值不會所以回傳undefined而不是10
//可以想成是先宣告再賦值,像下面這樣:
var b
console.log(b)
b = 10
用在function也很常見,讓程式碼function位置不用都 一定 要在呼叫上面。
可以先做呼叫,提高方便性。
test()
function test() {
console.log(123) //123
}
但用變數來宣告function又會報錯
test()
var test = function() {
console.log(123) //test is not a function -> 報錯
}
//這樣寫反而會報錯,因為只有宣告會提升
//可以想成是先宣告再賦值,像下面這樣:
var test
test()
test = function() {
console.log(123)
}
function test() {
console.log(a)
var a = "local"
function a() {
}
}
test() //[Function: a]
//function會優先於var,所以回傳Function: a
//可以想成下面這樣:
function test() {
function a() {
}
console.log(a)
a = "local"
}
test() //[Function: a],如果同時有兩個function a()後面會蓋掉前面的。
function test(a) {
console.log(a) //[Function: a]
var a = 456
function a() {
}
}
test(123)
//傳入參數也不會印出123或456,會以function a為優先。
優先性順序:1.function -> 2.arguments -> 3.var
用小練習來理解scope chain和hoisting(執行順序在最下面):
var a = 1;
function test(){
console.log("1.", a);
var a = 7;
console.log("2.", a);
a++;
var a;
inner();
console.log("4.", a);
function inner(){
console.log("3.", a);
a = 30;
b = 200;
}
}
test();
console.log("5.", a);
a = 70;
console.log("6.", a);
console.log("7.", b);
從 ECMAScript 來看 hoisting 的原理(規則)
規範沒有提到Hoisting但有講到Execution Contexts和Variable Instantiation,從這兩個來看。
Execution Contexts
在執行的時候functuon會依執行順序疊加在global上面,最上面的會先執行,執行完就消失,隨著程式碼會反覆堆高與減少,直到最底下的global執行完也等同整個程式執行完。如圖示:
圖片來自於影片與Huli文章,該文章也是引用自freecodecamp
Variable Instantiation
Every execution context has associated with it a variable object.
把它想成每個function會有一個object來存變數
function test() {
var a = 1
}
VariableObject {
a: 1
}
//VariableObject{}不是真實寫出來的,只是一個想成有這樣的位置存放function的值
當傳入值的時候,會幫參數初始化。
VariableObject {
a: 123 // 只有傳一個參數a:123
b: undefined // b初始值會undefined
}
function test(a, b) {
}
test(123)
當test內有function a 存在時傳進去的參數123會優先被取代
VariableObject {
a: 123
b: undefined //b從undefined變成function
}
function test(a, b) {
function b() {
}
}
test(123)
對變數的宣告,重覆的值不會被改變,沒有的才會被初始成undefined
VariableObject {
a: 123 //已經取得參數值,不會因為function b裡的var a=10而被改變
b: function //已經是function b,不會因為function b裡的var b=20而被改變
c: undefined //原本就沒有的才會被放進去。並給初始值undefined
}
function test(a, b) {
function b() {
var a = 10
var b = 20
var c = 30
}
}
test(123)
後面沒有再節錄規範原文,是直接看影片範例來理解。更詳細說明可以看參考資料Huli文章。
今天先講前半段,明天再繼續。
小題目解答先簡單放執行順序,明天再從執行環境的角度來重新理解。