派发通知发生在数据更新阶段,当数据更新时,就会触发set函数,我们接下来速览set的实现createSetter函数
function createSetter(shallow = false) {
return function set(
target: object,
key: string | symbol,
value: unknown,
receiver: object
): boolean {
// 条件1
let oldValue = (target as any)[key]
if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
return false
}
// 条件2
if (!shallow) {
if (!isShallow(value) && !isReadonly(value)) {
oldValue = toRaw(oldValue)
value = toRaw(value)
}
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value
return true
}
} else {
// in shallow mode, objects are set as-is regardless of reactive or not
}
const hadKey =
isArray(target) && isIntegerKey(key)
? Number(key) < target.length
: hasOwn(target, key)
const result = Reflect.set(target, key, value, receiver)
// don't trigger if target is something up in the prototype chain of original
// 条件3
if (target === toRaw(receiver)) {
if (!hadKey) {
trigger(target, TriggerOpTypes.ADD, key, value)
} else if (hasChanged(value, oldValue)) {
trigger(target, TriggerOpTypes.SET, key, value, oldValue)
}
}
return result
}
}
1.如果属性旧值是只读的ref值,且key要赋值的不是ref类型,则函数返回false,不能进行值的设置
示例如下:
import { ref, reactive, readonly } from 'vue';
const num = ref(1)
const readonlObj = readonly(num)
const obj = reactive({ key: readonlObj })
obj.key = 2 // TypeError: 'set' on proxy: trap returned falsish for property 'key'
console.log(obj)
2.shallow为false的前提下,如果当前对象不是数组,属性旧值是ref,且新值不是ref,则直接把新值赋值到旧值value上
示例如下:
import { ref, reactive } from 'vue';
const num = ref(1)
const obj = reactive({ key: num })
obj.key = 2
console.log(obj) // {key: Ref<2>}
3.如果属性是当前对象的属性,才触发派发操作,如果是原型链上对象的属性,则不触发派发操作。这比较好理解,如果不做限制,那么原型链上某个属性发生变化,那么所有实例都会受到影响,这不符合实际
现在知道是怎么派发了,那触发函数长哪样?下文我们再继续分析!
本人菜鸡,有问题望前辈及时指出,不胜感激!!