屬性描述符
ES5開始所有的屬性都有了屬性描述符,以表示屬性的一些特性佩微。
我們可以通過Object.getOwnPropertyDescriptor(...)查看屬性描述符。
let obj = {a: 'a'};
let descriptor = Object.getOwnPropertyDesciptor(obj, 'a');
//descriptor: {value: 'a', writable: true, enumerable: true, configurable: true}
這里我們只討論其中的writable(可寫)萌焰、configurable(可配置)哺眯,我們可以通過Object.defineProperety(...)來配置屬性描述符。
當設置了writable為false時扒俯,該屬性的值無法修改奶卓。
Object.defineProperty(obj, 'a', {writable: false});
obj.a = 'b'; //obj.a = 'a'
當設置了configurable為false時,無法重新配置該屬性的特性撼玄,且無法刪除該屬性夺姑,該操作是不可逆的。(唯一可以設置的情況是掌猛,將writable為true 改為writable為false)
Object.defineProperty(obj, 'a', {configurable: false});
delete obj.a //obj.a = 'a';
Object.defineProperty(obj, 'a', {configurable: true}); //Type Error
Object.defineProperty(obj, 'a', {writable: false});
obj.a = 'aa'; //obj = {a: 'a'}
禁止擴展
Object.preventExtensions(...)防止后續(xù)向?qū)ο笮略鰧傩浴?/p>
let obj = {a: 'a'};
Object.preventExtensions(obj);
obj.b = 'b'; //obj = {a: 'a'}
console.log(Object.isExtensible(obj)); //false
密封對象
Object.seal(...)可以創(chuàng)建一個密封的對象盏浙,該對象的屬性不可擴展、配置荔茬、刪除废膘,但可以修改。實際上該方法就是對對象先用Object.preventExtensions禁止擴展屬性慕蔚,再將對象所有屬性的configurable特性設置false丐黄。
let obj = {a: 'a', b: 'b'};
Object.seal(obj);
obj.c = 'c'; //obj = {a: 'a', b: 'b'}
delete obj.a;
delete obj.b; //obj = {a: 'a', b: 'b'}
obj.a = 'aa'; //obj = {a: 'aa', b: 'b'}
console.log(Object.isSealed(obj)); //true
凍結(jié)對象
Object.freeze(...)可以創(chuàng)建一個凍結(jié)的對象,該對象的屬性不可擴展坊萝、配置孵稽、刪除、修改十偶,是js中對象最高不可變性菩鲜。實際上該方法就是調(diào)用Object.seal(...)將對象設置成密封對象后,在將所有數(shù)據(jù)訪問屬性設置為writable:false惦积。
let obj = {a: 'a', b: 'b'};
Object.freeze(obj);
obj.c = 'c'; //obj = {a: 'a', b: 'b'}
delete obj.a;
delete obj.b; //obj = {a: 'a', b: 'b'}
obj.a = 'aa'; //obj = {a: 'a', b: 'b'}
console.log(Object.isFrozen(obj)); //true
這個方法是你可以應用在對象上的級別最高的不可變性接校,它會禁止對于對象本身及其任意直接屬性的修改(不過這個對象引用的其他對象是不受影響的)。
注意
這里對象中的不可變性都是淺不變性,如果屬性引用的是對象蛛勉、數(shù)組等引用類型鹿寻,該引用的對象、數(shù)組本身都是可變的(比如往數(shù)組里添加元素)诽凌,除非再把每個引用類型屬性遞歸凍結(jié)毡熏。
let obj = {a: [1, 2]};
Object.freeze(obj);
obj.a.push(3); //obj = {a: [1, 2, 3]}