Proxy 实现原理

  • Vue2.x 实现响应式数据的原理

    • 对象 类型数据的处理

      使用数据劫持的方式,通过 Object.defineProperty( )对属性的读取、修改进行拦截

      this.$set(this.a, "b", 2); //对象新增属性
      Vue.set(this.a, "b", 2);
      
      this.$delete(this.a, "b"); //对象删除属性
      Vue.delete(this.a, "b");
      
    • 数组 类型数据的处理

      通过重写数组的 7 个方法( push、pop、shift、unshift、splice、reverse、sort ),拦截对数组的修改,实现响应式数据

      this.$set(this.b, 0, "xxx"); //将数组索引为0的数据修改为 xxx
      Vue.set(this.b, 0, "xxx");
      
    • 缺点

      • 新增属性、删除属性时,页面不会更新( $set , $delect )
      • 直接通过数组下标修改数据时,页面不会更新
    • 实现

      Object.defineProperty(data, "a", {
        get() {}, //捕获数据读取时
        set() {}, //捕获修改数据时
      });
      
  • Vue3.x 实现响应式数据的原理

    let a = {
      a: 1,
      b: 2,
    };
    
    //创建Proxy实例对象,a 为源数据
    const p = new Proxy(a, {});
    
    • 当修改 Proxy 实例对象时
    p.a = 3; // a.a = 3
    

    修改代理对象时,源数据内部数据也会同步修改

    修改包含对数据的新增、修改、删除

    • 捕获数据的修改
    const p = new Proxy( a , {
      get ( target , propName ) {
          //target 为源数据,此处为 a
          //propName 为当前读取的属性名 此处可为 a、b
    
        //返回值为读取时获取的值
        return target[propName]
      },
    
      set ( target , propName , value ) {
          //target 为源数据,此处为 a
          //propName 为当前读取的属性名,此处可为 a、b
          //value 为修改属性时赋予的新值
    
        //将修改时的新值赋予给需要修改的属性
        target[propName] = value
      }
    
      deleteProperty ( target , propName ) {
           //target 同上
           //propName 同上
    
         //返回值为删除属性时外部接受到的值
         return delete target[propName]
      }
    } )
    
    • 读取数据时:使用 get 函数
    • 修改数据时:使用 set 函数
    • 删除数据时:使用 deleteProperty 函数
    • 新增数据时:使用 set 函数
  • Reflect 反射属性

    //修改属性
    Reflect.set(a, "b", 4);
    
    //读取属性
    Reflect.get(a, "b");
    
    //删除属性
    Reflect.deleteProperty(a, "b");
    

    通过反射属性,对对象进行数据的操作

    • Reflect 反射属性包含 Object 的方法和属性
    const b = Reflect.defineProperty(a, "c", 5);
    // true
    const c = Reflect.defineProperty(a, "c", 6);
    // false
    

    当代码有错误时,Reflect 通过返回值确定代码执行结果

    不抛出错误,中断程序执行

    可以避免使用 try... catch... 进行错误的捕获

上次更新:
贡献者: Roking-wang