有六种情况
1.target未定义或者是基础类型就抛出警告
// 1.target未定义或或者是基础类型就抛出警告
if (isUndef(target) || isPrimitive(target)) {
warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target))));
}
2.判断是否为数组,并判断key是不是有效索引,将数组的.length属性设置为最大值,调用数组的splice方法,将修改的数据变为响应式
// 2.判断是否为数组,并判断key是不是有效索引,
if (Array.isArray(target) && isValidArrayIndex(key)) {
// 判断下标和数组长度,将数组的.length属性设置为最大值
target.length = Math.max(target.length, key);
// 调用数组的splice方法,将修改的数据变为响应式
target.splice(key, 1, val);
// 返回对应的val
return val
}
3.如果这个属性在这个对象上,则设置属性为对应的属性值后直接返回val
// 3.如果这个属性在这个对象上,则设置属性为对应的属性值后直接返回val
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val
}
4.判断当前的目标对象是否是Vue实例,或者根数据对象,如果是则warn警告并返回(更新data无意义)
// 在getter的时候设置__ob__,获取响应式对象__ob__
var ob = (target).__ob__;
// 4.判断当前的目标对象是否是Vue实例,或者根数据对象,如果是则warn警告并返回
if (target._isVue || (ob && ob.vmCount)) {
warn(
'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.'
);
return val
}
- 当前的这个目标对象如果不是响应式对象则直接赋值返回
//5. 当前的这个目标对象如果不是响应式对象则直接赋值返回
if (!ob) {
target[key] = val;
return val
}
6.对象更新,defineReactive添加响应式属性,调用update,更新渲染视图
// 给目标对象对应的属性添加响应式
defineReactive(ob.value, key, val);
// 通知所有订阅者,调用update,更新渲染视图
ob.dep.notify();
return val
当新增属性时可以考虑对象合并的方法
this.obj={...this.obj,...{a:1,b:2}}
总结:
当set所设置的目标对象为数组时,则调用目标对象的splice方法将修改的数据变为响应式。
当set所设置的目标对象为对象时,首先判断这个属性是否在这个对象上,如果存在则设置属性为对应的属性值后直接返回val,然后判断目标对象是否为Vue实例或者根数据对象,如果是则warn警告后返回,再去判断这个目标对象是否是响应式的,如果不是响应式对象则直接赋值返回。最后在给目标对象的属性添加响应式,通知dep实例的所有订阅者进行更新。