标准答案
- 对象属性描述符用来描述一个属性能不能写、能不能枚举、能不能删除或重新配置,以及读取和设置时是否走访问器函数。
- 数据描述符包含 value 和 writable。value 是属性值,writable 决定数据属性能否被改写。
- 访问器描述符包含 get 和 set,用函数控制读取和设置。访问器描述符不能同时和 value、writable 混用。
- enumerable 决定属性是否会出现在 Object.keys、for...in、对象展开等常规枚举结果中。
- configurable 决定属性能否被删除,以及描述符能否被重新配置。Object.defineProperty 默认创建的 writable、enumerable、configurable 都是 false。
题目解析
对象字面量创建属性时,writable、enumerable、configurable 通常都是 true;Object.defineProperty 的默认值更保守。忘记写 enumerable 是很多手写代码看不到属性的原因。
不可枚举不等于不存在。Object.keys 看不到,不代表 Reflect.ownKeys 或 Object.getOwnPropertyDescriptor 看不到。
理解属性描述符能帮助理解 Vue 2 的 defineProperty 响应式、Object.freeze 的限制、以及一些库为什么要把内部字段设成不可枚举。
代码示例
下面示例展示数据描述符、访问器描述符和不可枚举属性。
JavaScript
const user = {}
Object.defineProperty(user, 'id', {
value: 1,
writable: false,
enumerable: true,
configurable: false
})
Object.defineProperty(user, 'secret', {
value: 'token',
enumerable: false
})
let firstName = 'Alice'
let lastName = 'Lee'
Object.defineProperty(user, 'fullName', {
get() {
return firstName + ' ' + lastName
},
set(value) {
;[firstName, lastName] = value.split(' ')
},
enumerable: true,
configurable: true
})
Object.keys(user) // ['id', 'fullName']
Object.getOwnPropertyDescriptor(user, 'secret').enumerable // false常见误区
- 误以为不可枚举属性不存在,只是常规枚举看不到。
- Object.defineProperty 忘记显式写 enumerable,导致属性不能被 Object.keys 看到。
- configurable 为 false 后还想重新定义属性类型。