Skip to content

Vue 的数据响应式原理是什么?

Vue 的数据响应式原理是通过 Object.definePropertyProxy 来实现的。Vue 在初始化时会对 data 对象中的属性进行递归遍历,使用 Object.defineProperty 将这些属性转换为 gettersetter。当数据发生变化时,setter 会通知依赖该数据的视图进行更新。

使用object.defineProperty

js
// 属性对应的依赖函数,设置函数集合(依赖可能不是一个函数)
const targetMap = new Map<string, Set<Function>>();
// 暂存当前需要收集的副作用函数
let activeEffect: Function | null = null;
function oberserver<T>(data: T) {
  if (!data || typeof data !== "object") return;
  for (const item in data) {
    // 忽略原型链上的属性
    if (Object.prototype.hasOwnProperty.call(data, item)) continue;
    let initValue = data[item];
    // 递归处理对象属性
    oberserver(initValue);
    Object.defineProperty(data, item, {
      get() {
        if (activeEffect) {
          // 获取当前属性对应的依赖函数
          let depsSet = targetMap.get(item);
          //   如果不存在则创建
          if (!depsSet) {
            depsSet = new Set<Function>();
            // 添加依赖函数
            targetMap.set(item, depsSet);
          }
          //   添加依赖函数
          depsSet.add(activeEffect);
        }
        return initValue;
      },
      set(newValue) {
        if (newValue === initValue) return;
        initValue = newValue;
        const deps = targetMap.get(item);
        deps?.forEach((fn) => {
          fn();
        });
      },
    });
  }
  return data;
}

// 收集依赖函数
function collect(...fn: Function[]) {
  fn.forEach((fun) => {
    activeEffect = fun;
    fun();
    activeEffect = null;
  });
}

使用proxy

js
const handler = {
  get(target, key, receiver) {
    console.log(`get ${key}`);
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    console.log(`set ${key}: ${value}`);
    return Reflect.set(target, key, value, receiver);
  }
};

const observed = new Proxy({}, handler);

这是我的个人文档