glownight

返回

Proxy 深度监听与 Vue3 响应式#


核心机制:懒递归代理#

function reactive(target) {
  return new Proxy(target, {
    get(target, key, receiver) {
      track(target, key);  // 依赖收集
      
      const result = Reflect.get(target, key, receiver);
      
      // 懒递归:访问时才深层代理
      return isObject(result) ? reactive(result) : result;
    },
    
    set(target, key, value, receiver) {
      const oldValue = target[key];
      const result = Reflect.set(target, key, value, receiver);
      
      if (hasChanged(value, oldValue)) {
        trigger(target, key);  // 触发更新
      }
      return result;
    }
  });
}
javascript

懒递归 vs 深度遍历#

Vue2(defineProperty)Vue3(Proxy)
初始化递归遍历所有属性访问时才代理深层对象
新增属性需 Vue.set自动支持新增/删除
数组重写 7 个方法原生支持索引和 length

依赖收集与触发#

// 全局状态
const targetMap = new WeakMap();
let activeEffect = null;

// 读取时收集
function track(target, key) {
  if (!activeEffect) return;
  
  let depsMap = targetMap.get(target);
  if (!depsMap) targetMap.set(target, depsMap = new Map());
  
  let dep = depsMap.get(key);
  if (!dep) depsMap.set(key, dep = new Set());
  
  dep.add(activeEffect);  // 组件订阅此属性
}

// 修改时触发
function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  
  depsMap.get(key)?.forEach(effect => effect());
}
javascript

使用示例#

const state = reactive({ 
  count: 0, 
  nested: { num: 1 } 
});

effect(() => {
  console.log(state.nested.num);  // 访问时自动代理 nested
});

state.nested.num++;  // 触发更新
state.newProp = 123; // 自动响应,无需 set
javascript
Proxy 深度监听与 Vue3 响应式
作者 glownight
发布于 2026年2月3日