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)

      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/19.html