今天我們要來解開物件的第二層魔法:「拷貝」與「不可變」。
前幾天我們知道,物件不是獨立存在的小盒子,而是「參考」同一份資料。
今天要學的,就是如何複製、分身、修改而不傷及原體。
今日的目標:
來看個陷阱:
const a = { name: '高高' }
const b = a
b.name = '周周'
console.log(a.name) // 會變成周周
因為js是「call by reference」,如果兩個變數指向同一個記憶體位址,改 b 也會改到 a。
所以,我們需要知道怎麼複製物件~
這邊還有一個錯誤的範例 → 直接指定(錯誤方式)
const arr1 = [1, 2, 3]
const arr2 = arr1
arr2[0] = 99
console.log(arr1) // [99, 2, 3](被改了!
兩個變數指向同一個記憶體位置,所以會連原本的arr1也被改了
正確的方式是用以下這幾種方式複製出「新的陣列」
淺拷貝只會複製「第一層」的屬性,只有第一層被複製,
若裡面還包著物件或陣列,仍然共用同一份記憶體。
常見作法有{ ...obj }(展開運算子):
const original = { name: '高高', info: { age: 18 } }
const copy = { ...original }
copy.name = '碩庭'
copy.info.age = 20
console.log(original.name) // 印出 高高(沒被改
console.log(original.info.age) // 印出 20(被改了!
要讓巢狀陣列也完全獨立就要用「深拷貝」,深拷貝會把巢狀物件都複製一份新的。
因為「內層」是物件型別,淺拷貝不會深層複製它~
所以要讓巢狀陣列也完全獨立,就要用「深拷貝」!
structuredClone() 是現代瀏覽器內建的深拷貝方法:
const original = { name: '高高', info: { age: 18 } }
const deepCopy = structuredClone(original)
deepCopy.info.age = 20
console.log(original.info.age) // 18(完全不受影響)
「不可變」的意思是:不要直接改原始資料,而是產生一個新的版本。
為什麼要這樣做呢?
舉例來說
const person = { name: '高高', age: 18 }
// 直接修改(不好)
person.age = 19
// 不可變更新(推薦)
const updatedPerson = { ...person, age: 19 }
console.log(person.age) // 18
console.log(updatedPerson.age) // 19
這樣一來,每次修改都像是在「版本更新」
v1 → v2 → v3
資料是乾淨的、可追蹤的。
![]()