Property flags and descriptors
Property flags
屬性除了值還有 3 個標誌,創造屬性時不會看到他們,因為預設皆為 true。
- writable– if- true, can be changed, otherwise it’s read-only.
- enumerable– if- true, then listed in loops, otherwise not listed.
- configurable– if- true, 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"; // ErrorNon-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)); // nameNon-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}); // ErrorObject.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
Was this helpful?