reactive
大约 1 分钟
前言
上一节实现的类无法实现对引用类型数据的操作捕获,所以这一节使用 Proxy 来实现对引用类型数据的操作捕获。
Vue2 使用的是 Object.defineProperty实现
Vue3 使用的是 Proxy实现
dep
修改一下上一节实现的 dep 类,移除 value 属性和 getter setter
let activeEffect;
class Dep {
  subscribers = new Set();
  depend() {
    if (activeEffect) {
      this.subscribers.add(activeEffect);
    }
  }
  notify() {
    this.subscribers.forEach((effect) => {
      effect();
    });
  }
}
reactive
在 vue3 中,reactive 函数接收的是一个引用类型的数据,使之具有响应式。
思路
接收引用类型的数据;
返回数据的代理;
实现
// WeakMap:只接受 object 作为 key;当 key 不被引用时,该 key 也就随之清除(垃圾回收)
const targetsMap = new WeakMap(); // 记录所有响应式对象的依赖
/**
 * @description: 获取指定值的 Dep 实例(记录着该值的所有依赖)
 * @param target 目标对象
 * @param key 键
 * @return {object} dep
 */
function getDep(target, key) {
  let depsMap = targetsMap.get(target);
  if (!depsMap) {
    depsMap = new Map();
    targetsMap.set(target, depsMap);
  }
  let dep = depsMap.get(key);
  if (!dep) {
    dep = new Dep();
    depsMap.set(key, dep);
  }
  return dep;
}
// 拦截器
const reactiveHandlers = {
  // receiver 解决 this 指向问题
  get(target, key, receiver) {
    const dep = getDep(target, key);
    // 收集依赖
    dep.depend();
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    const result = Reflect.set(target, key, value, receiver);
    const dep = getDep(target, key);
    // 触发依赖
    dep.notify();
    return result;
  },
};
/**
 * @description: 创建响应式对象
 * @param raw 要代理的对象
 * @return {object} proxy
 */
function reactive(raw) {
  return new Proxy(raw, reactiveHandlers);
}
创建响应式对象
const state = reactive({
  count: 1,
});
watchEffect(() => {
  console.log(state.count);
});
state.count++; // 2
总结
响应式的原理
- 访问属性时收集依赖
 - 修改属性时触发依赖