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)
内容版权声明:除非注明,否则皆为本站原创文章。