响应式原理-defineReactive
本篇将详细讲解,在 Observer 的 walk() 中通过遍历对象的属性调用的 defineReactive 这个方法是如何将对象的每一个属性转换成 getter/setter 的。
/**
* Define a reactive property on an Object.
*/
// 为一个对象定义一个响应式的属性
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
// 创建依赖对象实例
// 为当前这个属性收集依赖,即收集观察这个属性的所有 watcher
const dep = new Dep()
// 获取 obj 的属性描述符对象
const property = Object.getOwnPropertyDescriptor(obj, key)
// 如果当前属性是不可配置的,return
if (property && property.configurable === false) {
return
}
// 提供预定义的存取器函数
// cater for pre-defined getter/setters
// 如果有预设的set和get,先取出来并对其进行重写
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
// 如果只传了两个参数,需要手动的获取这个属性对应的 value
val = obj[key]
}
// 判断是否递归观察子对象,并将子对象属性都转换成 getter/setter ,返回子观察对象
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// 如果预定义的 getter 存在,则 value 等于 getter 调用的返回值
// 否则直接赋予属性值
const value = getter ? getter.call(obj) : val
// 如果存在当前依赖目标,即 watcher 对象,则建立依赖
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
// 如果属性是一个数组,则特殊处理收集数组对象依赖
if (Array.isArray(value)) {
dependArray(value)
}
}
}
// 返回属性值
return value
},
set: function reactiveSetter (newVal) {
// 如果预定义的 getter 存在,则 value 等于 getter 调用的返回值
// 否则直接赋予属性值
const value = getter ? getter.call(obj) : val
// 如果新值等于旧值或者新值旧值为 NaN 则不执行
/* 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()
}
// 如果没有 setter 直接返回,说明属性是只读的。
// #7981: for accessor properties without setter
if (getter && !setter) return
// 如果预定义 getter 存在,则调用,否则直接更新新值
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
// 如果新值是一个对象,观察子对象,并返回子对象的 observer 对象
childOb = !shallow && observe(newVal)
// 派发更新(发布通知)
dep.notify()
}
})
}