vue响应式原理

58 阅读1分钟

学习vue3源码,实现了一下简单的响应式原理。
需要学习掌握Proxy、Reflect、WeakMap、Map、Set

// 全局变量,保存当前依赖的回调
let activeFn = null;

// 依赖收集类
class Dep {
  constructor() {
    // 避免多次get同一值时重复添加
    this.list = new Set();
  }
  depend() {
    if (activeFn) {
      // 收集回调函数
      this.list.add(activeFn);
    }
  }
  notify() {
    // 触发回调
    this.list.forEach(fn => fn());
  }
}

// 数据结构
const wMap = new WeakMap();
const getDepend = (target, key) => {
  // 从weakMap中通过target查到当前对象的数据map
  let map = wMap.get(target);
  if (!map) {
    map = new Map();
    wMap.set(target, map);
  }
  // 从查询到的map中查询当前属性对应的depend
  let dep = map.get(key);
  if (!dep) {
    dep = new Dep();
    map.set(key, dep);
  }
  return dep;
};

// 监听函数
const watch = fn => {
  // 保存回调
  activeFn = fn;
  // 手动执行一次,收集依赖
  fn();
  activeFn = null;
};

// proxy代理
const reactive = obj => {
  return new Proxy(obj, {
    get(target, key, receiver) {
      // 添加依赖到对应map中
      const dep = getDepend(target, key);
      dep.depend();
      return Reflect.get(target, key, receiver);
    },
    set(target, key, newValue, receiver) {
      Reflect.set(target, key, newValue, receiver);
      // 触发对应依赖的回调
      const dep = getDepend(target, key);
      dep.notify();
    },
  });
};

const info = reactive({
  name: '李四',
  age: 20,
});

watch(() => {
  console.log('监听info.name改变', info.name);
});

setTimeout(() => {
  info.name = '张三';
}, 3000);