Skip to content

Vue3 用 Proxy 实现响应式

Proxy 实现响应式

  • 深度监听,性能更好
  • 可监听 新增/删除属性
  • 可监听数组变化
  • 但,无法兼容所有浏览器,无法 polyfill
js
// 创建响应式
function reactive(target = {}) {
  if (typeof target !== 'object' || target == null) {
    // 不是对象或数组,则返回
    return target;
  }
  // 代理配置
  const proxyConf = {
    get(target, key, receiver) {
      // 改进
      // 只处理本身(非原型的)属性
      const ownKeys = Reflect.ownKeys(target);
      if (ownKeys.includes(key)) {
        console.log('get', key); // 监听
      }
      const result = Reflect.get(target, key, receiver);
      // return result // 返回结果
      // 深度监听,把上面修改成下面
      return reactive(result);
      // 那么性能是如何提升?
      /**
       *  Object.defineProperty 一次性递归完
       *  Proxy 是 get 到哪一层,就递归到哪一层
       */
    },
    set(target, key, val, receiver) {
      // 改进
      // 重复的数据,不处理
      if (val === target[key]) {
        return true;
      }
      const ownKeys = Reflect.ownKeys(target);
      if (ownKeys.includes(key)) {
        console.log('已有的 key', key);
      } else {
        console.log('新增的 key', key);
      }
      const result = Reflect.set(target, key, val, receiver);
      console.log('set', key, val);
      console.log('result', result);
      return result; // 是否设置成功
    },
    deleteProperty(target, key) {
      const result = Reflect.deleteProperty(target, key);
      console.log('delete property', key);
      console.log('result', result);
      return result; // 是否删除成功
    },
  };
  // 生成代理对象
  const observed = new Proxy(target, proxyConf);
  return observed;
}
// 测试数据
const data = {
  name: 'zhangsan',
  age: 20,
  info: {
    city: 'shenzhen',
    a: {
      b: {
        c: {
          d: {
            e: 100,
          },
        },
      },
    },
  },
};
const proxyData = reactive(data);
// 测试
console.log(proxyData.age);
// get age
// 20
// 没有深度监听
console.log(proxyData.info.city);
// get info
// shenzhen
// 深度监听
console.log(proxyData.info.city);
// get info
// get city
// shenzhen
// 新增的 key
console.log((proxyData.age1 = 100));
// 新增的 key age1
// set age1 100
// result true
// 100

那么性能是如何提升?

  • Object.defineProperty 一次性递归完
  • Proxy 是 get 到哪一层,就递归到哪一层

基于 MIT 许可发布