vue2响应式原理
/*
* @Author: dezhao.zhao@hand-china.com
* @Date: 2021-08-28 16:57:47
* @Description:
*/
class Dep {
constructor() {
// 依赖保存器
this.subscribers = new Set();
}
// 收集依赖
depend = () => {
if (activeEffect) {
this.subscribers.add(activeEffect);
}
};
// 通知收集的依赖
notify = () => {
this.subscribers.forEach((effect) => {
effect();
});
};
}
// 用于保存依赖数据结构.....
// weakmap 对于对象的引用为弱引用,当外界不再对存储对象进行引用,weakmap中存储的对象会被回收
const targetMap = new WeakMap();
function getDep(target, key) {
// 根据target对象取出对应的map对象
let depsMap = targetMap.get(target);
if (!depsMap) {
depsMap = new Map();
targetMap.set(target, depsMap);
}
// 取出具体的dep对象
let dep = depsMap.get(key);
if (!dep) {
dep = new Dep();
depsMap.set(key, dep);
}
return dep;
}
// 响应式系统处理
function reactive(raw) {
// 将传入对象的每个key都加入响应式系统中
Object.keys(raw).forEach((key) => {
const dep = getDep(raw, key);
let value = raw[key];
Object.defineProperty(raw, key, {
get() {
// 保存依赖
dep.depend();
return value;
},
set(newValue) {
if (value !== newValue) {
// raw[key] = newValue 会导致递归 这里设置以及返回的数据都是value 不能直接对raw操作 会导致死循环递归调用
value = newValue;
dep.notify();
}
}
});
});
return raw;
}
// 用于临时保存 依赖函数
let activeEffect = null;
//
function watchEffect(effect) {
// 保存依赖了变量的函数或其他表达式
activeEffect = effect;
// 默认 首次执行依赖,且必须执行,如果不执行,不触发get 无法添加依赖
// 执行effect时就会访问对象属性,此时会把依赖的函数或表达式加入依赖收集中
effect();
// 恢复依赖收集,以便下次依赖添加
activeEffect = null;
}
const info = reactive({ name: 'zdz', age: 18 });
const info1 = reactive({ height: 1.88 });
watchEffect(function () {
console.log('watch1', info.name);
});
watchEffect(function () {
console.log('watch2', info.age);
});
watchEffect(function () {
console.log('watch3', info1.height);
});
info.name = 'newzdz';
info.age = 19;
info1.height = 2.0;
- 当修改响应式对象中的值时,添加了监听的都会重新执行
-
第一次watch1-3为首次添加监听执行,第二次为对象属性值变化响应式通知
image.png
网友评论