Proxy 的原理

  1. Proxy 是什么
    Proxy 是 ES6 引入的一个新特性,它可以对对象的基本操作(如属性读取、属性设置、枚举、函数调用等)进行拦截和自定义处理。Proxy 接收两个参数:目标对象(target)和处理程序对象(handler)。处理程序对象中可以定义各种拦截操作的方法,这些方法被称为陷阱(trap)。
    以下是一个简单的 Proxy 示例:
const target = {
  name: 'John',
  age: 30
};

const handler = {
  get(target, property) {
    console.log(`Getting property ${property}`);
    return target[property];
  },
  set(target, property, value) {
    console.log(`Setting property ${property} to ${value}`);
    target[property] = value;
    return true;
  }
};

const proxy = new Proxy(target, handler);

// 读取属性
console.log(proxy.name); // 会触发 get 陷阱

// 设置属性
proxy.age = 31; // 会触发 set 陷阱
2. Vue 3 中 Proxy 的应用原理
2.1 响应式数据创建
在 Vue 3 中,reactive 函数利用 Proxy 来创建响应式对象。reactive 函数接收一个普通对象作为参数,然后返回一个被 Proxy 包装后的对象。
以下是简化后的 reactive 实现思路:
function reactive(target) {
  const handler = {
    get(target, property, receiver) {
      // 收集依赖
      track(target, property);
      return Reflect.get(target, property, receiver);
    },
    set(target, property, value, receiver) {
      const oldValue = target[property];
      const result = Reflect.set(target, property, value, receiver);
      if (result && oldValue!== value) {
        // 触发更新
        trigger(target, property);
      }
      return result;
    }
  };

  return new Proxy(target, handler);
}

2.2 依赖收集(track)
当访问响应式对象的属性时,Proxy 的 get 陷阱会被触发。在 get 陷阱中,Vue 会收集依赖,也就是记录哪些副作用(如组件的渲染函数)依赖于这个属性。
以下是简化后的 track 函数实现:

const targetMap = new WeakMap();

function track(target, property) {
  if (!activeEffect) return;
  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }
  let dep = depsMap.get(property);
  if (!dep) {
    depsMap.set(property, (dep = new Set()));
  }
  dep.add(activeEffect);
}

2.3 触发更新(trigger)
当修改响应式对象的属性时,Proxy 的 set 陷阱会被触发。在 set 陷阱中,Vue 会检查属性值是否发生了变化,如果发生了变化,就会触发依赖更新,也就是执行之前收集的所有依赖该属性的副作用。
以下是简化后的 trigger 函数实现:

function trigger(target, property) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(property);
  if (dep) {
    dep.forEach(effect => effect());
  }
}
  1. 总结
    Vue 3 利用 Proxy 的拦截功能实现了响应式系统。当访问响应式对象的属性时,Proxy 的 get 陷阱会收集依赖;当修改属性时,Proxy 的 set 陷阱会触发依赖更新。这种机制使得 Vue 能够自动追踪数据的变化,并在数据变化时更新相关的 DOM。与 Vue 2 中使用的 Object.defineProperty 相比,Proxy 可以拦截更多的操作,并且可以对整个对象进行拦截,不需要对每个属性进行单独处理,因此实现更加简洁和高效。
posted @ 2025-04-01 21:32  jialiangzai  阅读(123)  评论(0)    收藏  举报