Javascript學習---屬性的識別符號和描述符
到目前為止,我們已經知道物件可以儲存屬性,屬性以簡單的鍵值對形式儲存在物件中,但是物件的屬性其實是一個複雜和可調的東西。
屬性的標誌
一個物件屬性除了鍵和值外,還有三個特殊的屬性,被叫做屬性識別符號:
(1)writable:如果為true,則該屬性是可寫的,否則為只讀;
(2)enumerable:如果為true,則屬性可以被迴圈列舉出,否則則不能被列舉;
(3)configurable:如果為true,則屬性可以被刪除或者屬性值能夠被修改,否則則不能;
預設情況下屬性識別符號都為true。
Object.getOwnPropertyDescriptor()
為了能夠獲得屬性的識別符號,我們可以使用Object.getOwnPropertyDescritor()來檢視,它的語法如下:
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
其中,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()來操作,具體語法如下:
Object.defineProperty(obj, propertyName, descriptor)
其中descriptor引數指的是屬性識別符號的修改內容,下面是一個例子:
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 } */
因為descriptor的內容只包含value值,故其餘的三個屬性標識為false
屬性只讀read-only
我們可以修改writable為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
一般情況下,我們可以使用for...in來迴圈列舉出物件的所有屬性,例如:
let user = {
name: "John",
toString() {
return this.name;
}
};
// By default, both our properties are listed:
for (let key in user) alert(key); // name, toString
但如果設定屬性的enumerable為false後,該屬性就不能被迴圈列舉出,例如:
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
這裡,toString()屬性方法就不能沒列舉出來,同時使用Object.keys()也不能列舉出來,如下:
alert(Object.keys(user)); // name
屬性不可配置non-configurable
如果我們設定屬性的configurable標識為false,那麼那屬性就不能被刪除,甚至屬性的值也不能修改,例如Math類的PI屬性:
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": 3.141592653589793,
"writable": false,
"enumerable": false,
"configurable": false
}
*/
這裡可以看出,Math.PI是不可寫、不可列舉和不可配置的,如果我們要刪除PI或者修改它,則會報錯:
Math.PI = 3; // Error
// delete Math.PI won't work either
需要注意的是,一旦配置了configurable為false,在後面就不能設定該屬性的識別符號了,即便是使用defineProperty()也無法修改,例如:
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()
Object.defineProperties()允許我們一次性新增屬性並修改屬性的描述符,它的語法如下:
Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
});
這是例子:
Object.defineProperties(user, {
name: { value: "John", writable: false },
surname: { value: "Smith", writable: false },
// ...
});
Object.getOwnPropertyDescriptors()
為了一次性獲取物件所有屬性的描述符,我們可以使用Object.getOwnPropertyDescriptors(),它返回物件所有屬性的描述符,例如:
const obj = {
[Symbol('foo')]: 123,
get bar() { return 'abc' },
};
console.log(Object.getOwnPropertyDescriptors(obj));
// Output:
// { [Symbol('foo')]:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
這裡要注意的是,Object.getOwnPropertyDescriptors()返回的描述符包含了Symbol屬性