簡單來說,這三個Object的methods都是用來「鎖定」物件,讓物件無法被修改或刪除屬性(props),但各自有不同的影響範疇:
可新增屬性 | 可刪除屬性 | 可修改屬性 | |
preventExtensions | ❌ | ✅ | ✅ |
seal | ❌ | ❌ | ✅ |
freeze | ❌ | ❌ | ❌ |
用一個簡單的例子來一步一步說明
先建立一個物件,在正常情況之下,我們可以任意新增、修改、刪除物件中的屬性:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 建立一個物件,在預設狀態下可以任意新增、修改、刪除屬性 | |
const obj = { a: 1, b: 2, c: 3 } | |
obj.d = 4 | |
console.log(obj) // { a: 1, b: 2, c: 3, d: 4 } 預設狀態下可以新增 | |
obj.d = 5 | |
console.log(obj) // { a: 1, b: 2, c: 3, d: 5 } 預設狀態下可以修改 | |
delete obj.d | |
console.log(obj) // { a: 1, b: 2, c: 3 } 預設狀態下可以刪除 |
然後我們用Object.preventExtensions(obj)來限制擴展,就會發現當我們嘗試要新增屬性時不會發生作用:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 使用 preventExtensions 防止新增 | |
Object.preventExtensions(obj) | |
obj.d = 4 | |
console.log(obj) // { a: 1, b: 2, c: 3 } 無法新增 | |
obj.c = 4 | |
console.log(obj) // { a: 1, b: 2, c: 4 } 可以修改 | |
delete obj.c | |
console.log(obj) // {a: 1, b: 2} 可以刪除 |
接著我們用Object.seal(obj)來防止新增並限制刪除,此時物件僅剩下可修改既有屬性的功能:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 使用 seal 防止新增與禁止刪除 | |
Object.seal(obj) | |
obj.c = 3 | |
console.log(obj) // { a: 1, b: 2 } 無法新增 | |
obj.b = 3 | |
console.log(obj) // { a: 1, b: 3 } 可以修改 | |
delete obj.b | |
console.log(obj) // { a: 1, b: 3 } 無法刪除 |
接著再以Object.freeze(obj)來鎖定物件,便會發現物件已無法再做任何修改:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 使用 freeze 防止新增,禁止修改與刪除 | |
Object.freeze(obj) | |
obj.c = 3 | |
console.log(obj) // { a: 1, b: 3 } 無法新增 | |
obj.b = 2 | |
console.log(obj) // { a: 1, b: 3 } 無法修改 | |
delete obj.b | |
console.log(obj) // { a: 1, b: 3 } 無法刪除 |
對於子物件的影響
這三個methods執行後,都不會影響子物件的任何操作。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const obj = { a: 1, b: { c: 2, d: 3 } } | |
Object.freeze(obj) | |
obj.a = 2 | |
console.log(obj) // { a: 1, b: { c: 2, d: 3 } } a 無法修改 | |
obj.b.c = 4 | |
console.log(obj) // { a: 1, b: { c: 4, d: 3 } } b中的c可以修改 |
如何解除?
答案是沒辦法。一旦鎖定過的部分,就無法回頭。也就是說,當你執行過freeze,即便再執行一次seal,還是會整個都鎖定住。
不過,關於解除,如果只是一個簡單的Object,還可以用Object.assign來clone一份:
obj = Object.assign({}, obj);
obj = Object.assign({}, obj);
但如果是Class, Proxy…etc. 就沒辦法這麼簡單去做一個類似復原的動作了。