主题
defineReactive 定义响应式对象
defineReactive
方法源码如下
js
export function defineReactive( obj: object, key: string, val?: any, customSetter?: Function | null, shallow?: boolean, mock?: boolean) {
const dep = new Dep();
// 获取 obj.key的属性描述, 也就是原始对象的属性描述 Object.defineProperty的第三个参数
const property = Object.getOwnPropertyDescriptor(obj, key);
if (property && property.configurable === false) { // 若是不可设置的属性, 直接跳过不做处理
return;
}
// cater for pre-defined getter/setters
// 原始对象身上的 getter/setter
const getter = property && property.get;
const setter = property && property.set;
if (
(!getter || setter) &&
(val === NO_INITIAL_VALUE || arguments.length === 2) // 兼容取到属性值
) {
val = obj[key];
}
let childOb = !shallow && observe(val, false, mock); // 对每一个值递归observe处理
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() { // getter
const value = getter ? getter.call(obj) : val; // 取到属性的值
// 依赖收集操作
if (Dep.target) {
if (__DEV__) {
dep.depend({
target: obj,
type: TrackOpTypes.GET,
key
});
} else {
dep.depend();
}
if (childOb) {
childOb.dep.depend();
if (isArray(value)) {
dependArray(value);
}
}
}
return isRef(value) && !shallow ? value.value : value; // TODO:
},
set: function reactiveSetter(newVal) { // setter
const value = getter ? getter.call(obj) : val; // 取到属性的旧的值
if (!hasChanged(value, newVal)) { // 对比新旧值是否有变化, 没有变化则停止操作(提高性能)
return;
}
if (__DEV__ && customSetter) { // 开发环境时候时候的操作, 跳过
customSetter();
}
if (setter) { // 有setter则设置新值
setter.call(obj, newVal);
} else if (getter) { // TODO:只有getter则停止操作
// #7981: for accessor properties without setter
return;
} else if (!shallow && isRef(value) && !isRef(newVal)) { // 旧值是ref , 新值部署ref, 也是赋值
value.value = newVal;
return;
} else {
val = newVal; // 最后
}
childOb = !shallow && observe(newVal, false, mock); // 对新值递归observe
if (__DEV__) { // 开发环境
dep.notify({
type: TriggerOpTypes.SET,
target: obj,
key,
newValue: newVal,
oldValue: value
});
} else {
dep.notify(); // 派发更新
}
}
});
return dep;
}
在defineReactive
中, 会为对象的每一个属性实例化一个Dep
, 用于收集依赖;
接着获取当前属性的描述符, 之后会判断当前属性是否是可以由Object.defineProperty
处理的, 若是不支持处理(例如:冻结后的属性), 则直接跳过, 这也是为何有点场景下Object.freeze
可以提高性能的原因
若是可操作的属性, 会获取到属性的值, 然后对每一个属性值进行observe
递归处理, 最终返回一个childOb
接着就是为每一个属性Object.defineProperty
get
取值之前会进行依赖的收集dep.depend();
, 但是需要通过if (Dep.target)
才会执行依赖收集操作,Dep.target
是什么先放一放, 后面会说到. 依赖收集中, 会递归进行收集set
设置新值之前, 会先对比新值与旧值, 若是没变化则不会进行设置, 避免触法更新 下面还会进行一系列判断, 最终目的都是设置新值 最后还会通过dep.notify()
来派发更新
defineReactive
设置响应式过程中的依赖收集
和派发更新
, 都离不开Dep
, 那么Dep
到底是什么, 有什么作用, 我们来一探究竟