Property flags and descriptors
Property flags
屬性除了值還有 3 個標誌,創造屬性時不會看到他們,因為預設皆為 true。
writable
– iftrue
, can be changed, otherwise it’s read-only.enumerable
– iftrue
, then listed in loops, otherwise not listed.configurable
– iftrue
, the property can be deleted and these attributes can be modified, otherwise not.
// Object.getOwnPropertyDescriptor() 可以完整取得屬性的資訊
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
let user = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
// Object.defineProperty() 可以改變屬性的標誌
Object.defineProperty(obj, propertyName, descriptor)
// 屬性存在會改變標誌,屬性不存在會創造,但標誌皆為 false
let user = {};
Object.defineProperty(user, "name", {
value: "John"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "John",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
Read-only
// writable: false 不可修改
let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Error: Cannot assign to read only property 'name'...
// 對新增的屬性要列出標誌的值,不然皆為 false
let user = { };
Object.defineProperty(user, "name", {
value: "Pete",
// for new properties need to explicitly list what's true
enumerable: true,
configurable: true
});
alert(user.name); // Pete
user.name = "Alice"; // Error
Non-enumerable
// 內建的 toString 不會顯示在迴圈,但自定義的 toString 會出現在迴圈
let user = {
name: "John",
toString() {
return this.name;
}
};
// 默认情况下,我们的两个属性都会列出:
for (let key in user) alert(key); // name, toString
// enumerable: false toString 不會出現在迴圈
let user = {
name: "John",
toString() {
return this.name;
}
};
Object.defineProperty(user, "toString", {
enumerable: false
});
// Now our toString disappears:
for (let key in user) alert(key); // name
// 也不會出現在 Object.keys()
alert(Object.keys(user)); // name
Non-configurable
// configurable: false 不能藉由 Object.defineProperty() 刪除或修改屬性
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": 3.141592653589793,
"writable": false,
"enumerable": false,
"configurable": false
}
*/
// 不能刪除屬性
Math.PI = 3; // Error
// delete Math.PI won't work either
// configurable: false 沒有回頭路,會鎖住所有屬性資訊無法更改
let user = { };
Object.defineProperty(user, "name", {
value: "John",
writable: false,
configurable: false
});
// won't be able to change user.name or its flags
// all this won't work:
// user.name = "Pete"
// delete user.name
// defineProperty(user, "name", ...)
Object.defineProperty(user, "name", {writable: true}); // Error
Object.defineProperties
// syntax
Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
});
// example
Object.defineProperties(user, {
name: { value: "John", writable: false },
surname: { value: "Smith", writable: false },
// ...
});
Object.getOwnPropertyDescriptors
// 可以用迴圈複製物件
for (let key in user) {
clone[key] = user[key]
}
// 用 Object.getOwnPropertyDescriptors() + Object.defineProperties() 式更好的方法
// 可以複製所有屬性的資訊
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
Last updated