1. 程式人生 > 實用技巧 >JS中禁止物件屬性擴充套件、密封物件、凍結物件

JS中禁止物件屬性擴充套件、密封物件、凍結物件

物件常量屬性

概念:將屬性的writable和configurable設定為false;

//將屬性的writable和configurable設定為false
var damu={};
Object.defineProperty(damu,"wife",{
    value:"fbb"
})
Object.defineProperty(damu,"wife",{
    value:"fbb2"
});
//無法更改,無法刪除。可以新增
//console.log(damu);//報錯,Cannot redefine property

damu.wife="damu"
delete damu.wife;
console.log(damu);//{wife: "fbb"}

damu.wife2="fbb2";
console.log(damu);//{wife2: "fbb2", wife: "fbb"}

禁止屬性擴充套件

概念
如果一個物件可以新增新的屬性,則這個物件是可擴充套件的,讓這個物件變的不可擴充套件,也就是不能再有新的屬性;由於屬性描述符是對屬性的管理,所以想禁止物件擴充套件,不能使用屬性描述符來控制,而是需要呼叫其他的物件的方法。
兩種有關物件屬性擴充套件的物件方法:

Object.isExtensible 方法:Object.isExtensible() 方法判斷一個物件是否是可擴充套件的(是否可以在它上面新增新的屬性)。

語法: Object.isExtensible(obj)
引數: obj 需要檢測的物件;

預設情況下,建立的物件預設是可擴充套件

//新物件預設是可擴充套件的無論何種方式建立的物件
//使用的是字面量方式
var
empty = {a:1}; console.log(Object.isExtensible(empty) === true);//true //等價於 使用屬性描述符 empty = Object.create({},{ "a":{ value : 1, configurable : true,//可配置 enumerable : true,//可列舉 writable : true//可寫 } }); console.log(Object.isExtensible(empty) === true);//true //建立屬性的方式 var damu={}; Object.defineProperty(damu,"wife",{ value:"fbb" }) console.log(Object.isExtensible(damu) === true);//true

Object.preventExtensions 方法:方法讓一個物件變的不可擴充套件,也就是永遠不能再新增新的屬性,並且返回原物件。

語法:Object.preventExtensions(obj);
引數:obj 將要變得不可擴充套件的物件;
var damu = {};
Object.defineProperty(damu,'wife',{
    value:'lbb'
});
console.log(damu);//{wife: "lbb"}
Object.preventExtensions(damu);
//  damu.age = 18;
//  console.log(damu);//{wife: "lbb"}

 (function fail(){
       "use strict";
       damu.d = "4";//throws a TypeError
   })();
console.log(damu);//Cannot add property d, object is not extensible

描述:

如果一個物件可以新增新的屬性,則這個物件是可擴充套件的。preventExtensions 可以讓這個物件變的不可擴充套件,也就是不能再有新的屬性。
需要注意的是不可擴充套件的物件的屬性通常仍然可以被刪除。
嘗試給一個不可擴充套件物件新增新屬性的操作將會失敗,不過可能是靜默失敗(預設情況),也可能會丟擲 TypeError 異常(嚴格模式)。
注意:Object.preventExtensions 只能阻止一個物件不能再新增新的自身屬性,仍然可以為該物件的原型新增屬性。

密封物件

概念:
密封物件是指那些不可擴充套件的,且所有自身屬性都不可配置的(non-configurable)物件。
或者可以說,密封物件是指那些不能新增新的屬性,不能刪除已有屬性,以及不能修改已有屬性的可列舉性、可配置性、可寫性,但可能可以修改已有屬性的值的物件。
可用方法:在禁止物件擴充套件(Object.preventExtensions(obj);的基礎上把現有屬性的configurable都調整為false;

//設定物件即使不可擴充套件又不可配置
var damu = {};
Object.defineProperty(damu,'wife',{
    value:'lbb'
    //此時預設的configurable和writable都為false的。
});
console.log(damu);//{wife: "lbb"}
Object.preventExtensions(damu);

damu.age = 18;
delete damu.wife;//{wife: "lbb"}
console.log(damu);//{wife: "lbb"};
//證明不可配置、不可擴充套件。但是這種設定的過程很麻煩,嘗試使用簡單的物件方法來設定密封物件。

兩種有關密封屬性的方法

Object.isSealed 方法:方法判斷一個物件是否是密封的(sealed)。

語法 :Object.isSealed(obj);
引數:obj 將要檢測的物件;

描述:如果這個物件是密封的,則返回 true,否則返回 false。

//使用Object.preventExtensions設定為不可擴充套件,再設定不可配置,則成為密封了。
var damu = {};
Object.defineProperty(damu,'wife',{
    value:'lbb'
    //此時預設的configurable和writable都為false的。
});
Object.preventExtensions(damu);
console.log(Object.isSealed(damu));//true

Object.seal() 方法:可以讓一個物件密封,並返回被密封后的物件。

語法:Object.seal(obj)
引數:obj 將要被密封的物件
var damu = {};
Object.defineProperty(damu,'wife',{
    value:'lbb'
    //此時預設的configurable和writable都為false的。
});
console.log(Object.getOwnPropertyDescriptor(damu,"wife"));//{value: "lbb", writable: false, enumerable: false, configurable: false}
Object.seal(damu);
console.log(Object.isSealed(damu));//true
//靜默失敗
damu.d = 'd';
delete damu.wife;
console.log(damu);//{wife: "lbb"}

console.log(Object.getOwnPropertyDescriptor(damu,"wife"))

描述:

通常情況下,一個物件是可擴充套件的(可以新增新的屬性)。

密封一個物件會讓這個物件變的不能新增新屬性,且所有已有屬性會變的不可配置。
屬性不可配置的效果就是屬性變的不可刪除,以及一個數據屬性不能被重新定義成為訪問器屬性,或者反之。但屬性的值仍然可以修改。
嘗試刪除一個密封物件的屬性或者將某個密封物件的屬性從資料屬性轉換成訪問器屬性,結果會靜默失敗或丟擲TypeError 異常(嚴格模式)。
不會影響從原型鏈上繼承的屬性。但 proto ( ) 屬性的值也會不能修改。

凍結物件

概念:
一個物件是凍結的(frozen)是指它不可擴充套件,所有屬性都是不可配置的(non-configurable),且所有資料屬性(data properties,指那些沒有取值器getter或賦值器setter的屬性)都是不可寫的(non-writable);
或則說 凍結物件是指那些不能新增新的屬性,不能修改已有屬性的值,不能刪除已有屬性,以及不能修改已有屬性的可列舉性、可配置性、可寫性的物件。也就是說,這個物件永遠是不可變的;
可用方法:在密封物件(Object.seal(obj))的基礎上把現有屬性的writable都調整為false:

廣州品牌設計公司https://www.houdianzi.com PPT模板下載大全https://redbox.wode007.com

//在密封物件(Object.seal(obj))的基礎上把現有屬性的writable都調整為false
var damu = {};
Object.defineProperty(damu,'wife',{
    value:'lbb',
    //writable:true
});
//密封
Object.seal(damu);
//防擴充套件
Object.preventExtensions(damu);
damu.age = 18;
delete damu.wife;
damu.wife = 'zdy';
console.log(damu);//{wife: "lbb"};

兩種有關密封屬性的方法

Object.isFrozen 方法:方法判斷一個物件是否被凍結(frozen)。

語法: Object.isFrozen(obj)
引數:obj 被檢測的物件

Object.freeze() 方法:可以凍結一個物件。

語法:Object.freeze(obj);
引數:obj 將要被凍結的物件;
var damu = {wife:'lbb'};
console.log(Object.getOwnPropertyDescriptor(damu,"wife"));
//{value: "lbb", writable: true, enumerable: true, configurable: true}
//凍結物件
Object.freeze(damu);
console.log(Object.getOwnPropertyDescriptor(damu,"wife"));
//{value: "lbb", writable: false, enumerable: true, configurable: false}
damu.age = 18;
delete damu.wife;
damu.wife = 'zdy';
console.log(damu);//{wife: "lbb"}

描述:

凍結物件的所有自身屬性都不可能以任何方式被修改。
任何嘗試修改該物件的操作都會失敗,可能是靜默失敗,也可能會丟擲異常(嚴格模式中)。
資料屬性的值不可更改,訪問器屬性(有getter和setter)也同樣(但由於是函式呼叫,給人的錯覺是還是可以修改這個屬性)。
如果一個屬性的值是個物件,則這個物件中的屬性是可以修改的,除非它也是個凍結物件。

//淺不變形
var damu={wifes:{wife1:"fbb",wife2:"lyf",wife3:"zdy"}};
damu.wifes.wife1="lbb";
console.log(damu);//wifes:{wife1: "lbb", wife2: "lyf", wife3: "zdy"}

//深層次凍結
var damu={
    wifes:{wife1:"fbb",wife2:"lyf",wife3:"zdy"}
};
Object.freeze(damu);
//遍歷呼叫凍結方法,將物件屬性內的物件全部凍結。
for(item in damu){
    Object.freeze(damu[item]);
}
damu.wifes.wife1="lbb";
console.log(damu);//wifes:{wife1: "fbb", wife2: "lyf", wife3: "zdy"}