对象的属性类型
JavaScript 中的对象的属性包括数据属性和访问器属性,在 JavaScript 引擎的内部实现中定义了用于描述属性(property)的特性(attribute)。规范中将特性放在了两对方括号中以此表示它们是内部值,在 JavaScript 中不能直接访问这些特性。
数据属性
数据属性的特性包括:
-
[[Configurable]]
:表示能否通过delete
删除属性从而重新定义属性;能否修改属性的特性;或能否把属性修改为访问器属性。默认值为true
。 -
[[Enumerable]]
:表示能否通过for-in
循环返回属性。默认值为true
。 -
[[Writable]]
:表示能够修改属性的值。默认值为true
。 -
[[Value]]
:包含这个属性的数据值。读取属性值的时候从这个位置读,写入属性值的时候把新值保存在这个位置。默认值为undefined
。
修改属性的特性
由于属性的特性不能直接访问,因此要修改属性的特性需要使用 Object.defineProperty()
方法。
var person = new Object();
Object.defineProperty(person, 'name', {
configurable: false,
writable: false,
value: 'Nicholas'
});
console.log(person.name); // Nicholas
person.name = 'Greg';
console.log(person.name); // Nicholas
delete person.name;
console.log(person.name); // Nicholas
在调用 Object.defineProperty()
方法时,如果不指定, [[Configurable]]
、 [[Enumerable]]
、 [[Writable]]
特性的默认值都为 false
。
注:严格模式下,对只读的属性进行赋值操作会导致抛出错误;对不可配置的属性调用 delete
也会导致错误。一旦将属性修改为不可配置后再调用 Object.defineProperty()
方法修改除 [[Writable]]
之外的特性都会导致错误。
访问器属性
访问器属性的特性包括:
-
[[Configurable]]
:表示能否通过delete
删除属性从而重新定义属性;能否修改属性的特性;或能否把属性修改为访问器属性。默认值为true
。 -
[[Enumerable]]
:表示能否通过for-in
循环返回属性。默认值为true
。 -
[[Get]]
:在读取属性时调用的函数 getter。默认值为undefined
。 -
[[Set]]
:在写入属性时调用的函数 setter。默认值为undefined
。
访问器属性不能直接定义,必须使用 Object.defineProperty()
来定义。
var book = {
_year: 2017,
edition: 1
};
Object.defineProperty(book, 'year', {
get: function () {
return this._year;
},
set: function (newValue) {
if (newValue > this.year) {
this.edition += newValue - this.year;
this._year = newValue;
}
}
})
book.year = 2020;
book.year = 2023;
console.log(book.edition + ', ' + book.year); // 7, 2023
在读取访问器属性时,会调用 getter 函数,这个函数负责返回有效的值;在写入访问器属性时会调用 setter 函数并传入新值作为参数。
注:不如果只为访问器属性指定 getter 或 setter 函数,意味着该访问器属性是只读或只写的。
同时定义多个属性
使用 Object.defineProperties()
方法可以通过描述符一次定义多个属性。
var book = {};
Object.defineProperties(book, {
_year: {
writable: true,
value: 2017
},
edition: {
writable: true,
value: 1
},
year: {
get: function () {
return this._year;
},
set: function (newValue) {
if (newValue > this.year) {
this.edition += newValue - this.year;
this._year = newValue;
}
}
}
});
book.year = 2020;
book.year = 2023;
console.log(book.edition + ', ' + book.year); // 7, 2023