JavaScript 對象不變性介紹
1. 基本概念
對象不變性在任何編程語言中都是一個重要的概念。它會限制對象修改并防止不需要的更改。簡而言之,對象的不變性就是將它的狀態(tài)變?yōu)橹蛔x的,下面就來看看在 JavaScript 中的對象不變性。?
在JavaScript
中,一個對象可以有一個或多個屬性。每個屬性都是一個鍵值對,
下面是一個對象:
const user = { ?? ?name: 'CUGGZ', ? age: 24, }
這里使用const
關(guān)鍵字定義了一個對象,它具有兩個屬性。默認(rèn)情況下,對象是可變的,也就是說,我們可以給對象添加新屬性,修改現(xiàn)有屬性或者刪除已有屬性。而在某些情況下,我們可能希望對象是不可變的,即不能添加新屬性,也不能修改和刪除已有屬性。
2. Object.freeze()
顧名思義,freeze()
就是用來凍結(jié)對象的。只需要將不想被更改的對象傳遞給它,就會返回該對象的不可變版本:
const user = { ?? ?name: 'CUGGZ', ? age: 24, } const freezeUser = Object.freeze(user); freezeUser.age = 18; console.log(freezeUser.age) // 24
這時,新的對象就不可變了,相當(dāng)于被凍結(jié)了。?
在JavaScript
了,提供了一個Object.isFrozen()
,它可以用來判斷一個對象是否被凍結(jié):
Object.isFrozen(user) ?// false Object.isFrozen(freezeUser) ?// true
需要注意的是, Object.freeze()
方法不會影響嵌套對象,對于嵌套對象,凍結(jié)后仍然是可以操作的:
const user = { ?? ?name: 'CUGGZ', ? age: 24, ? article: { ? ?? ?title: 'learn javascript', ? ? number: 1234 ? } } const freezeUser = Object.freeze(user); freezeUser.age = 18 freezeUser.article.number = 666; console.log(freezeUser.age) ? ? ? ? ? ? // 24 console.log(freezeUser.article.number); // 666
可以看到,使用Object.freeze()
方法凍結(jié)的對象,age是不可以更改的,但是嵌套對象的number
屬性還是可以修改的。如果需要凍結(jié)嵌套對象使其不可變,就需要使用循遞歸來逐級凍結(jié),下面是一個簡單的遞歸凍結(jié)實現(xiàn):
const deepFreeze = obj => { ? Object.keys(obj).forEach(prop => { ? ? if (typeof obj[prop] === 'object') { ? ? ?? ?deepFreeze(obj[prop]); ? ? } ? }); ? return Object.freeze(obj); }; deepFreeze(user);
Object.freeze()
方法除了可以用來凍結(jié)對象以外,還可以用于凍結(jié)數(shù)組,使其不可變:
const number = [1, 2, 3, 4, 5]; const freezeNumber = Object.freeze(number); freezeNumber.push(6);
此時就會報錯了:
VM210:3 Uncaught TypeError: Cannot add property 5, object is not extensible
3. Object.seal()
Object.seal()
顧名思義就是密封對象,它是另一種使對象不可變的方法。相對于freeze(),Object.seal() 方法僅保護(hù)對象不能添加和刪除屬性,它允許更新現(xiàn)有的屬性。
const user = { ?? ?name: 'CUGGZ', ? age: 24, } const sealUser = Object.seal(user); sealUser.age = 18; delete sealUser.name; console.log(sealUser) ? // {name: 'CUGGZ', age: 18}
可以看到,我們識圖刪除對象中的name
屬性,刪除失?。欢薷囊延械腶ge屬性,修改成功。?
Object.seal()
方法和Object.freeze()
一樣,對于嵌套的對象,是無法實現(xiàn)不可變的,如果想要實現(xiàn),同樣要使用遞歸來一層層來密封對象。?
JavaScript同樣提供了一個Object.isSealed()
方法來確認(rèn)對象的密封狀態(tài):
Object.isSealed(user) ? ? ?// false Object.isSealed(sealUser) ?// true
4. const關(guān)鍵字?
你是否會認(rèn)為,使用const關(guān)鍵字也能達(dá)到相同的結(jié)果呢?實際上,他們是不一樣的,當(dāng)我們使用const
關(guān)鍵字來創(chuàng)建對象時,它會阻止我們重新分配值,但是我們可以更新、添加、刪除已有對象的屬性:
const user = { ?? ?name: 'CUGGZ', ? age: 24, } delete user.age; user.height = 180; user.name = 'hello'; console.log(user); ?// {name: 'hello', height: 180}
而如果我們給user重新賦值,那么就會報錯了:
Uncaught TypeError: Assignment to constant variable.
因此,const關(guān)鍵字僅僅是提供了賦值的不變性,而不會提供值的不變性(對于對象來說)。
5. 總結(jié)
本文簡單介紹了兩種可以用于使JavaScript
不可變的方法。簡而言之,Object.seal()
方法會阻止更新、刪除和向?qū)ο筇砑有聦傩?,Object.seal()只會阻止添加和刪除屬性。、
除此之外,JavaScript
還提供了一個Object.preventExtensions()
方法,該方法可以讓一個對象變的不可擴(kuò)展,也就是永遠(yuǎn)不能再添加新的屬性。
const user = { ?? ?name: 'CUGGZ', ? age: 24, } const newUser = Object.preventExtensions(user); newUser.height = 180; console.log(newUser); ?// ?{name: 'CUGGZ', age: 24}
最后來看看它們?nèi)齻€的對比:
方法/操作 | 讀取 | 創(chuàng)建 | 更新 | 刪除 |
---|---|---|---|---|
Object.freeze() | ?? | ? | ? | ? |
Object.seal() | ?? | ? | ?? | ? |
Object.preventExtensions() | ?? | ? | ?? | ?? |
到此這篇關(guān)于JavaScript 對象不變性介紹的文章就介紹到這了,更多相關(guān)JavaScript 對象不變性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript復(fù)制粘貼與clipboardData的使用
window.clipboardData可以實現(xiàn)復(fù)制與粘貼的操作,下面有個小示例,想學(xué)習(xí)的朋友可以參考下2014-10-10

Extjs4中tree的拖拽功能(可以兩棵樹之間拖拽) 簡單實例

Electron點(diǎn)擊穿透不規(guī)則窗體的透明區(qū)域的實現(xiàn)

JavaScript中在光標(biāo)處插入添加文本標(biāo)簽節(jié)點(diǎn)的詳細(xì)方法