Vue源码解析之数据响应系统的使用(10)
set函数主要是设置属性值和触发依赖。
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
首先也是获取原来的属性值。为什么有这一步呢?因为要跟新值做比较,如果新旧值相等,就可以直接返回不用接下来的操作了。在if条件中,newVal === value这个我们都明白,那后面这个(newVal !== newVal && value !== value)条件是什么意思呢?
这是因为一个特殊的值NaN
NaN === NaN // false
如果newVal !== newVal,说明新值是NaN;如果value !== value,那么旧值也是NaN。那么新旧值也是相等的,也不需要处理。
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
在非生产环境下,如果customSetter函数存在,将执行该函数。customSetter是defineReactive的第四个参数,上面我们看initRender的时候有传过这个参数:
defineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, () => {
!isUpdatingChildComponent && warn(`$attrs is readonly.`, vm)
}, true)
第四个参数是一个箭头函数,当修改vm.$attrs时,会打印警告信息$attrs是只读的。所以customSetter的作用就是打印辅助信息。
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
如果存在getter不存在setter的话,直接返回。getter和setter就是属性自身的get和set函数。
下面就是设置属性值。如果setter存在的话,调用setter函数,保证原来的属性设置操作不变。否则用新值替换旧值。
最后是这两句代码:
childOb = !shallow && observe(newVal) dep.notify()
如果新值也是一个数组或纯对象的话,这个新值是未观测的。所以在需要深度观测的情况下,要调用observe对新值进行观测。最后调用dep.notify()触发依赖。
处理数组
看完了纯对象的处理,再来看一下数组是怎么转换为响应式的。数组有些方法会改变数组本身,我们称之为变异方法,这些方法有:push pop shift unshift reverse sort splice,如何在调用这些方法的时候触发依赖呢?看一下Vue的处理。
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
内容版权声明:除非注明,否则皆为本站原创文章。

