通常情况下,我们通过 . 或者 [] 给对象添加属性:
const o = {}
o.name = 'barwe'
o['age'] = 8
实际上对象的某个属性的操作和特性不仅仅是存值取值这么简答,比如只读属性、存取值时进行一些额外的操作,这些用上面这种定义属性的方式是不能实现的。上面这种简单赋值的方式实际上已经指定了一些默认操作,例如值是可写的,属性可以通过 Object.keys() 访问到等。
Object.defineProperty() 方法提供了一个定制属性特性的方式,基本语法是:
defineProperty<T>(o: T, p: PropertyKey, attributes: PropertyDescriptor & ThisType<any>): T;
其中
o是待添加或者修改属性的对象,它可以是一个原生的 JS 对象或者 DOM 对象p是属性名称,类型为string | number | symbolattributes对属性特性的描述对象
属性描述对象 PropertyDescriptor 的结构如下:
interface PropertyDescriptor {
configurable?: boolean;
enumerable?: boolean;
value?: any;
writable?: boolean;
get?(): any;
set?(v: any): void;
}
configurable为真表示可以使用Object.defineProperty()方法再次对属性特性进行配置,或者使用delete语句移除该属性。默认为false,即一经配置不能再次配置,而且不能将属性从对象中移除。enumerable为真时,对对象属性的枚举将包含该元素,典型的就是Object.keys()方法。默认为false,即枚举或者迭代对象时该属性是隐藏的。value指定了属性的初始值,默认为undefined。writable为真时表示该属性可以通过赋值操作符修改其值。默认为false,即不能修改初始值。get取值器,无参数,返回值作为属性值,默认为undefinedset存值器,以待存值作为参数,无返回值,默认为undefined
从上面的描述中我们可以知道,默认情况下:
- 普通方法定义的属性可以
delete掉,defineProperty方法定义的属性不行 - 普通方法定义的属性可以枚举,
defineProperty方法定义的属性不行 - 普通方法定义的属性值可以再次修改,
defineProperty方法定义的属性不行 - 普通方法定义的属性一般没有存取器,
defineProperty方法定义的属性可以添加,这也是 vue2 响应式原理的基础
参考资料:
评论区