Dive into Object.defineProperty
语法
Object.defineProperty(obj, prop, descriptor)
返回值:传入的 obj
描述
通过赋值创建的属性默认是可枚举 (for…in \ Object.keys),可以修改值,也可以被删除的。而 Object.defineProperty 可以修改这些特性。
默认通过 Object.defineProperty 添加的属性是不可修改且不可枚举的。
两种形式的描述符
- data descriptor 数据描述符
- accessor descriptor 访问器描述符
两种描述符都是对象,共享以下键值:
- configurable
- enumerable
数据描述符特有:
- writable
- value
访问器描述符特有:
- set
- get
描述符只能为其一,如果有 (value || writable) && (set || get) 则报错
回顾:对象属性类型
与描述符对应的,对象属性也有两种类型
- 数据属性
- 访问器属性
直接赋值的属性都是数据属性
1 | var obj = { a: 1 }; |
与描述符的键值对应的属性特性表现在这些内部值上 [[Configurable]]
、 [[Enumerable]]
、[[Writable]]
、[[Value]]
按上述方式定义的属性,前三个特性都是 true
访问器属性必须用 Object.defineProperty
来定义
1 | var obj = {}; |
几种特性的作用
Configurable
能否用 delete 删除属性,能否修改属性的特性,或者能否在数据属性和访问器属性间切换
如果 Configurable 为 false:
- 新的 Configurable 为 true,报错
- 新的 Enumerable 与旧的不一致,报错
- 由数据属性变为访问器属性或反之,报错
- 保持为数据属性,旧的 Writable 为 false,新的 Writable 为 true,报错
- 保持为数据属性,旧的 Writable 为 false,新的 Value 跟旧的不一样,报错
https://tc39.es/ecma262/#sec-validateandapplypropertydescriptor
总结一下 Configurable 为 false 时能修改的特性:
- writable:true -> false
- writable: true & value: a -> b
Writable
为 false 时,不能重新赋值,但如果 Configurable 为 true,可以通过 define value 修改值
Enumerable
是否可以在 for...in
和 Object.keys()
中被枚举
NOTE:
- 不管 Enumberable 是 true 还是 false,Symbol 类型的 key 都不会在上述方法被枚举
...
展开运算符会包含 Symbol,且只有 Enumerable 为 true 的属性被枚举