JavaScript 筆記:型別、Hoisting 與 TDZ
基本型別 (Primitive) 與物件型別 (Object)
在 JavaScript 中,所謂的 "值" 主要分為兩大類:
- 基本型別 (Primitive Types):
Number、String、Boolean、Undefined、Null、Symbol、BigInt。 - 物件型別 (Object Types):
Object Literal、Array、Functions等。
基本型別的存放位置
基本型別存於 執行堆疊 (Execution Stack)。 例如:
變數 dog1 最初指向某個記憶體位址 0001,值為 "Jumo"。
當重新賦值 "Judas" 時,會指向新的位址 0002,不會改變原本的值。

物件型別的存放位置
物件型別則存於 堆內存 (Heap),堆疊中的變數會保存一個參考位址,指向 Heap 中的實際資料。
兩者其實共享同一個 Heap 物件,因此修改其中一方會影響另一方。

物件複製方法
倘若要避免複製物件內容做改動時,連帶影響原物件,可以使用 Object.assign() 的方式。
但需要特別注意的是, Object.assign() 屬於非深層複製 (not deep clone), Object.assign() 僅會複製屬性值。若來源物件的值是參照到一個子物件 (object in object),它只會複製它的 reference,如下方程式碼。
將物件轉成字串再轉回物件
另外一種複製方法比較 tricky,透過 JSON.stringify() 將物件轉成字串,再透過 JSON.parse() 將字串轉成物件傳入變數。
提升 (Hoisting)
在 JavaScript 中,某些宣告會在程式執行前被提升。
函式宣告 (Function Declaration)
可在宣告前呼叫,因為整個函式會被提升。
var 宣告的變數
透過 var 宣告的變數也會被提升,算是在 JavaScript 提升機制中的副產物,一般而言,呼叫未被宣告的變數時,會出現 sahHi is not defined 的錯誤,但若呼叫後再透過 var 宣告 (如下方程式碼),則會出現 undefined,因為執行過程中, var 已經被偷偷被提升至前方,但是它的值並沒有一起被提升,等同於 var sayHi 被提升到 console.log 前面,但是 ="hihi" 並沒有跟著上去。
暫時死區 (Temporal Dead Zone, TDZ)
若在 let 或 const 宣告前使用變數,會出現錯誤,因為該區域處於 TDZ。
TDZ 存在的目的在於強制變數先宣告再使用,避免難以察覺的錯誤。
變數與函式特性總覽
| 類型 | 是否提升 | 初始值 | 作用域 |
|---|---|---|---|
| 函式宣告 (function declaration) | YES | 實際函式 | Block (strict mode) |
| 函式運算式 / 箭頭函式 (function expr/arrow) | 取決於使用 var 或 let/const | ||
| var 宣告 | YES | undefined | Function |
| let / const 宣告 | No | 未初始化 (TDZ) | Block |