JS物件-不可擴充套件物件、密封物件、凍結物件
阿新 • • 發佈:2019-01-22
JS中的不可擴充套件物件、密封物件、凍結物件
在JavaScript
中,可以對物件的許可權進行配置,通過配置,可將物件設定為不可擴充套件物件、密封物件、凍結物件等,以達到保護物件屬性的目的。
不可擴充套件物件
如果一個物件可以新增新的屬性,則這個物件是可擴充套件的。Object.preventExtensions()
將物件標記為不再可擴充套件,因此它將永遠不會具有超出它被標記為不可擴充套件的屬性。注意,一般來說,不可擴充套件物件的屬性可能仍然可被刪除。嘗試將新屬性新增到不可擴充套件物件將靜默失敗或丟擲TypeError
(最常見但不排除其他情況,如在strict mode
中)。
Object.preventExtensions()
一旦使其不可擴充套件,就無法再物件進行擴充套件。
/**
* 使用Object.preventExtensions()方法來阻止物件擴充套件
* 不可擴充套件物件不能繼續新增新屬性與新方法
* 可以修改原屬性與原方法
*/
var obj = {
a: 'a',
b: ['b']
};
// 通過Object.preventExtensions()來阻止擴充套件
Object.preventExtensions(obj);
// 嚴格模式下報錯,非嚴格模式下靜默失敗
obj.c = 'c';
console.log(obj); // { a: 'a', b: [ 'b' ] }
function changeObj() {
"use strict"
obj.d = 'd';
console.log(obj);
}
try {
changeObj();
} catch (ex) {
console.error("error: " + ex.message); // error: Cannot add property d, object is not extensible
}
// 仍可以修改已有的屬性值
obj.a = 'c';
obj.b.push('b2');
console.log(obj);
// 使用Object.isExtensible()可以檢測物件是否可擴充套件
var obj2 = {
name: "obj2"
}
console.log(Object.isExtensible(obj)); // false
console.log(Object.isExtensible(obj2)); // true
密封物件
密封物件不可擴充套件,而且已有的屬性成員[[configurable]]
特性將被設定成false
(意味著不能刪除屬性和方法,但是可修改已有屬性值)
/**
* 使用Object.seal()可以將物件密封
* 密封物件不可擴充套件
* 已有的屬性成員[[configurable]]特性將被設定成false(意味著不能刪除屬性和方法,但是可修改已有屬性值)
*/
let obj = {
a: 'a',
b: ['b']
};
Object.seal(obj);
// 非嚴格模式下靜默失敗
delete obj.a;
obj.c = 'c';
console.log(obj); // { a: 'a', b: [ 'b' ] }
// 嚴格模式下丟擲異常
try {
try {
(function add_d() {
"use strict"
obj.d = 'd';
})();
} catch (ex) {
console.error("add_d:" + ex.message); // add_d:Cannot add property d, object is not extensible
} finally {
(function delete_b() {
"use strict"
delete obj.b;
})();
}
} catch (ex) {
console.error('delete_b: ' + ex.message); // delete_b: Cannot delete property 'b' of #<Object>
}
// 可以修改屬性值
obj.a = 'a2';
console.log(obj.a); // 'a2'
// 通過Object.isSealed()方法可以判斷物件是否被密封
let obj2 = {
name: 'obj2'
};
console.log(Object.isSealed(obj)); // true
console.log(Object.isSealed(obj2)); // false
// 被封閉的物件同時不可擴充套件
console.log(Object.isExtensible(obj)); // false
console.log(Object.isExtensible(obj2)); // true
凍結物件
最嚴格的防止篡改級別是凍結物件,凍結的物件既不可以擴充套件,又是密封的,而且物件資料屬性的[[writable]]特性會被設定為false。 如果定義[[Set]]函式,訪問器屬性仍然是可寫的
/**
* 使用Object.freeze()方法可以凍結物件
* 凍結物件(frozen object)既不可擴充套件,又是密封的,而且物件的[[writable]]特性會被設定為false
* 如果定義[[Set]]函式,訪問器屬性仍然是可寫的
*/
let obj = {
a: 'a',
b: ['b']
}
let obj2 = {
name: 'obj2',
val: 'hello'
}
// 使用set函式定義一個存取描述符
Object.defineProperty(obj, 'set_obj2', {
configurable: true,
enumerable: true,
get: () => {
return obj2.val;
},
set: (val) => {
obj2.val = val;
}
})
// 凍結物件
Object.freeze(obj);
// 非嚴格模式下靜默失敗
obj.c = 'c';
console.log(obj.c); // undefined
delete obj.a;
console.log(obj.a); // 'a'
obj.a = 'a2';
console.log(obj.a); // 'a'
// [[set]]函式 訪問器屬性仍然可寫
obj.set_obj2 = 'haha'
console.log(obj.set_obj2); // 'haha'
// 嚴格模式下丟擲異常
try {
try {
(function add_d() {
"use strict"
obj.d = 'd';
})();
} catch (ex) {
console.error("add_d:" + ex.message); // add_d:Cannot add property d, object is not extensible
} finally {
(function delete_b() {
"use strict"
delete obj.b;
})();
}
} catch (ex) {
console.error('delete_b: ' + ex.message); // delete_b: Cannot delete property 'b' of #<Object>
}
// 仍然修改obj.b
try {
(function change_b() {
"use strict"
obj.b.push('b2');
console.log(obj.b); // [ 'b', 'b2' ]
})();
} catch (ex) {
console.error('change_b: ' + ex.message);
}
// 使用Object.isFrozen()方法檢測凍結物件
console.log(Object.isFrozen(obj)); // true
console.log(Object.isSealed(obj)); // true
console.log(Object.isExtensible(obj)); // false
console.log(Object.isFrozen(obj2)); // false
console.log(Object.isSealed(obj2)); // false
console.log(Object.isExtensible(obj2)); // true