JS 中对象的属性有两种类型:数据属性和访问器属性。
一个属性要么为数据属性,要么为访问器属性,不能既是数据属性又是访问器属性,会抛出错误。
// 错误 let person = {} Object.defineProperty(person, 'name', { value: 'Lee', get: function() { return 'Mary' } }) console.log(person.name)
数据属性:
let person = {
name: 'Lee', // name 属性就是数据属性
}
let person = new Object()
person.name = 'Lee' // name 属性就是数据属性
Object.defineProperty(person, 'name', {
value: 'Lee', // name 属性就是数据属性
})
数据属性的特性:
数据属性有四个描述其行为的特性:
[[Configurable]]
:表示能否通过 delete 删除属性;是否可以修改它的特性;是否可以将它修改为访问器属性。是否可以修改它的特性:是指一旦修改过
[[Configurable]]
特性后,就不能再修改[[Configurable]]
和[[Enumerable]]
特性了,会报错。[[Enumerable]]
:表示能否通过for-in
循环或者Object.keys()
返回属性。[[Writable]]
:表示能否修改属性的值。[[Value]]
:表示这个属性的属性值。写入属性值的时候,把值保存在这个位置;读取属性值的时候,从这个位置读。默认值为 undefined。
数据属性的特性的默认值:
- 通过
new object()
或者对象字面量的方式为对象添加的属性,其[[Configurable]]
、[[Enumerable]]
、[[Writable]]
特性默认都为 true。let person = { name: 'Lee' } // configurable、enumerable、writable 都为 true
- 通过
Object.defineProperty()
定义的属性,对于方法没有明确定义的特性,默认为 false。let person = {} Object.defineProperty(person, "name", { value: 'Lee' }) // configurable、enumerable、writable 都为 false Object.defineProperty(person, 'name', { configurable: true value: 'Mary' }) // configurable 为 true,enumerable、writable 为 false
访问器属性:
访问器属性可以使用 Object.defineProperty()
来定义。
let person = {}
Object.defineProperty(person, 'age', {
get: function() {
return 18
}
})
console.log(person.age) // 18。 age 属性就是访问器属性
访问器属性的特性:
访问器属性有四个描述其行为的特性:
-
[[Configurable]]
:表示能否通过 delete 删除属性;是否可以修改它的特性;是否可以将它修改为数据属性。默认值为 false。 -
[[Enumerable]]
:表示能否通过for-in
循环或者Object.keys()
返回属性。默认值为 false。 -
[[Set]]
:在写入属性时调用的函数。通过此方法就可以监听设置属性值的过程了。let person = {} Object.defineProperty(person, "name", { // 只要设置 person.name 的值,就会调用 set 方法,并且将值作为参数传入 set: function(value) { console.log(`set 方法被调用了,value 为 ${value}`) } }) person.name = 'Lee'
-
[[Get]]
:在读取属性时调用的函数。通过此方法就可以监听获取属性值的过程了。var person = {} var _name = '' Object.defineProperty(person, "name", { set: function(value) { _name = value }, // 只要获取 person.name 的值,就会调用 get 方法 get: function() { console.log(`get 方法被调用了`) return _name // 不能直接这样返回,会不停地调用 get 方法造成死循环 // return obj.name } }) person.name = 'Lee' console.log(person.name)
// 也可以通过下面的方式,但是不常用 var person = { _name: '', // setter 方法 set name(value) { this._name = value }, // getter 方法 get name() { return this._name } } person.name = 'Lee' console.log(person.name)
修改数据属性或访问器属性的特性:
要修改某个数据属性或访问器属性的特性,要使用 Object.defineProperty()()
方法。
Object.defineProperty()()
方法接收三个参数:属性所在的对象、属性的名字和一个属性描述符对象,如果是数据属性,那么属性描述符对象的属性必须是 [[Configurable]]
、[[Enumerable]]
、[[Writable]]
和 [[Value]]
,如果是访问器属性,那么属性描述符对象的属性必须是 [[Configurable]]
、[[Enumerable]]
、[[Set]]
和 [[Get]]
,设置它们的值,就可以修改对应的特性。返回值是修改后的对象。
Object.defineProperty(person, 'name', {
configurable: false, // 配置 name 属性无法删除
})
delete person.name
console.log(person) // {"name": "Lee"}。name 属性仍然存在
要修改多个数据属性或多个访问器属性的特性,要使用 Object.defineProperties()
方法。
let person = {
name: 'Lee',
age: 18,
}
Object.defineProperties(person, {
name: {
configurable: false, // 设置 name 属性不可删除
},
age: {
writable: false, // 设置 age 属性不可修改值
},
})
delete person.name
person.age = 20
console.log(person) // {name: 'Lee', age: 18}
获取数据属性或访问器属性的属性描述符:
可以使用 Object.getOwnPropertyDescriptor()
方法来获取某个数据属性或某个访问器属性的属性描述符。
let person = {}
var _name = ''
Object.defineProperty(person, 'name', {
set: function(value) {
_name = value
},
get: function() {
return _name
},
})
person.name = 'Lee'
console.log(Object.getOwnPropertyDescriptor(person, 'name'))
可以使用 Object.getOwnPropertyDescriptors()
方法来获取某个对象全部属性的属性描述符。
const person = {
name: 'Lee',
age: 18
}
console.log(Object.getOwnPropertyDescriptors(person))