该方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。应当直接在object构造器上调用此方法,而不是在任意一个object类型的实例上调用。
Object.defineProperty(obj, prop, descriptor)
参数:
obj:要定义属性的对象
prop:要定义或修改的属性名称或symbol
descriptor:要定义或修改的属性描述符
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由getter函数和setter函数所描述的属性。一个描述符只能是这两者其中之一,不能同时是两者。
左对齐 | 右对齐 | 居中对齐 |
---|---|---|
单元格 | 单元格 | 单元格 |
单元格 | 单元格 | 单元格 |
属性名 | configurable | enumerable | value | writable | get | Set |
---|---|---|---|---|---|---|
作用 | 是否可配置对象(删除属性) | 是否可枚举 | 是否可以修改对象 | 获取obj.key | 将修改的值重新赋值 | |
默认值 | false | false(也就是object.defineproperty定义的属性默认是不能被遍历的) | undefined | false | undefined | undefined |
数据描述符 | 可有 | 可有 | 可有 | 可有 | 不可有 | 不可有 |
存取描述符 | 可有 | 可有 | 不可有 | 不可有 | 可有 | 可有 |
Object.defineProperty(obj, key, {
// 1.value
enumerable: true, // 4.可以枚举
configurable: true, // 2.可以配置对象,删除属性
// writable: true // 3.可以修改对象
// get,set设置时不能设置writable和value,它们代替了 二者是互斥的 可以去看数据描述符和存取描述符
// 5.获取obj.key的时候就会调用get方法
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
// 6.将修改的值重新赋值
// 当我们更新data的时候,会触发set方法,执行dep.notify()方法
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})