前言
hoisting (提升) 也是常常被拿出來詢問的觀念,所以我決定要好好地記錄下來,拆成多篇記錄,由淺入深。
hoisting (提升)
使用一連串的範例來了解 hoisting 做了些什麼:
1 | console.log(b); // b is not defined |
因為辦法使用未宣告的變數。
但如果改成這樣子寫,就不會出錯了。
1 | console.log(a); // undefined |
這裡就是 hoisting 的一個特性,可以想像成它把所有的宣告提升到第一行,也就是說這段程式碼與下列這段程式碼的結果是一樣的:
1 | var a; |
但必須注意的是,hoisting 並不是真的物理性的把程式碼給拉到第一行。
從這邊可以知道一些 hoisting 的特性:
- 變數宣告會被提升,賦值不會
除了變數之外,其實函式也具有 hoisting 特性,但在介紹之前,先簡單複習一下函式陳述式 (Function Statements) 與函式表示式 (Function Expressions),或者點一下[JavaScriptWeird]No.26 函式表示式與函式陳述句複習。
函式表示式與函式陳述式
1 | function greet() { |
上面是函式陳述式,下面是函式表示式
1 | var anonymousGreet = function greet() { |
這邊只要知道這樣就可以了,接著來看範例。
1 | test(); |
這個範例的 hoisting 就算是 JavaScript 的初學者一定也遇過,因為 hoisting 的關係,所以允許把函式寫在呼叫該函式的下方,這在某些程式語言是做不到的,而我們也可以把這段程式想像成這樣,結果是一樣的:
1 | function test(){ |
但如果函式寫成表示式的話,就沒有提升的效果了。
1 | test(); // test is not a function |
其實原因很簡單,因為我們一開始看的範例已經得知:
只有變數宣告會被提升,賦值不會
也就是說這段程式碼可以看成這樣:
1 | var test; // undefined |
由於變數 test
的值是 undefined
,並不是函式所以無法被呼叫。
對現況再做個總整理:
- 變數宣告會被提升,賦值不會
- 函式陳述式會被提升,函式表示式不會 (因為提升的是變數宣告)
最後再來個陷阱題
1 | var a = 'global'; |
可能會很直覺的回答變數 a
會印出 global
,因為 test
函式內並沒有看到變數 a
。
但這邊事實上會印出 undefined
,因為 hoisting 會發生在變數的 scope 裡面,也就是說我們可以想像成這樣:
1 | var a = 'global'; |
可…可惡,陷阱真多!
後記
關於 hoisting 的基礎觀念大概是這樣,但其實 hoisting 背後還有相當深的觀念需要了解,特別推薦 Huli 大大的作品 - 我知道你懂 hoisting,可是你了解到多深?