JavaScript 物件深入淺出重點整理
資料型別 (Data Type)
JavaScript 的型別主要分兩大類別,分別是原始型別 (Primitive type) 及參考型別 (Reference type)。
- Primitive type
- Boolean
- Null
- Undefined
- Number
- String
- BigInt
- Symbol(於 ECMAScript 6 新定義)
- Reference type
- Object: Primitive type 以外的都屬於 Object 型別。例:
Object {}
、Array []
、Function ()
。
- Object: Primitive type 以外的都屬於 Object 型別。例:
Primitive type 和 Reference type 都是 call by value。不一樣的是儲存的東西。結束!
有人會說 Reference type 是 call by reference 或 call by sharing (這個比較符合我的意思和理解)。但是請先去看這篇:值 (value)、指標 (pointer/address)、參考 (reference)。
Primitive types call by value
1 | let x = 5, y = 10; |
call by value:將 x, y 的值 copy 一份給 a, b。
swap() 執行完畢後 x, y 不會互換,a, b 會互換。
Reference types call by value
1 | let x = { name: "Jenifer" }, |
call by value:一樣將 x, y 的值 copy 一份給 a, b。但是,因為儲存的不是物件本身,而是物件的位址,所以有很多陷阱和地雷要注意。
swap() 執行完畢後 x, y 不會互換,a, b 會互換。
如果改成:
1 | let x = { name: "Jenifer" }, |
使用 物件名稱.屬性名稱 = 值
會在同樣的記憶體位址增加屬性。因為 b
和 x
儲存一樣的記憶體位址,所以印出和 x
相同的結果。
使用 const 還是可以對屬性修改
因為沒有修改儲存的記憶體位址,僅修改屬性,不會報錯。注意:物件中的屬性名稱只會唯一存在。
1 | const x = { name: "Jenifer" }; |
重新指定記憶體位址會報錯。
splice()
、pop()
、push()
屬於修改屬性的函式。
slice()
是回傳一個新的陣列的函式。
1 | function newStaff(obj) { |
利用 Object.keys()
淺層複製
The
Object.keys()
method returns an array of a given object’s own enumerable property names, iterated in the same order that a normal loop would.
Object.keys()
回傳一個新的陣列,依序列舉出屬性名稱。
1 | const x = { |
注意:像是陣列的物件,有著任意 key 順序,使用 Object.keys()
會自動將其排序。
array-like object with random key ordering
1 | const fruits = { |
參考資料:
MDN Web Docs - Object.keys()
淺層複製
1. 展開運算子 (Spread Operator) { ...obj }
或 [ ...obj ]
淺層會有新的記憶體位址,但是深層的記憶體位址就一樣。改動新物件時會更動到舊物件,不是好的複製。
1 | const x = { |
2. 會回傳一個新物件、陣列的方法
a. Object.keys()
、for-in loop
。
b. 僅 Array: Array.map( x => x )
、Array.filter(() => true)
等。
c. 僅 Object: Object.assign({}, obj)
(array 也可以用,但會變物件)。對於 obj 來說 Object.assign({}, obj)
和 { ...obj }
基本上是一樣的。
深層複製
1. JSON.parse(JSON.stringify(obj))
1 | const x = { |
2. structuredClone(obj)
ECMAScript 2021 新提供了 structuredClone()
,這是一個用於深層複製的內建函式。
1 | const newX2 = structuredClone(x); |
補充資料:
structuredClone()
Can I use structuredClone?
奇怪的物件
1 | let a = { |
從第六行可以看出來有 Hoisting 的特性,a.y
或是說 b.y
早就已經被創造好,被賦予 undefined
。因此在第六行時,情況如下圖。
第八行 a
被賦予新物件。而 a = { name: "Mary" }
是表達式,會回傳 { name: "Mary" }
,因此 a.y
或是說 b.y
也被賦予新物件。
參考資料:
六角學院:JavaScript 常見考題破解:物件傳值?傳參考?