Vue中的Proxy比defineProperty到底好在哪

164 阅读1分钟

想要监听数据的变化就必须通过数据劫持,Proxy和defineProperty都能做数据劫持,但是数据劫持的方式不同。

核心都是对属性的读取和修改都要变成函数

vue2中defineProperty的做法

在vue源码中对对象进行了深度遍历对象中的每个属性做观察

      const obj = {
         name:'ohh',
         friendA:{
         name:'AAA',
         age:18,
         friends:{...}
      }
      function _isObject (v){
        return typeof v === 'object' && v != null;
      }
      function observe(obj) {
        for (const k in obj) {
          let v = obj[k]
          if(_isObject(v)){
            observe(v);
          }
          Object.defineProperty(obj, k, {
            get(){
              console.log(k,'读取');
              return k;
            },
            set(val){
              if(val != v){
                console.log(k,'更改')
                v = val
              }
            }
          })
        }
      }
      // 观察者模式
      observe(obj)
      obj.name;
      obj.name = "ahhh";

缺点:

  • 1.性能差
  • 2.如果对已经被观察的对象新增属性时,新的属性不会被观察(所以vue2中需要使用$set新增属性)

vue3中的Proxy做法

直接将对象变成一个新的代理对象,通过代理对象去做数据劫持

      const obj = {
        name: "ohh",
        friendA: {
          name: "AAA",
          age: 18,
        },
      };
      function _isObject(v) {
        return typeof v === "object" && v != null;
      }
      function observe(obj) {
        const proxy = new Proxy(obj, {
          get(target, k) {
            let v = target[k];
            if (_isObject(v)) {
              v = observe(v);
            }
            console.log(k, "读取", v);
            return v;
          },
          set(target, k, val) {
            if (target[k] != val) {
              console.log(k, "更改");
              target[k] = val;
            }
          },
        });
        return proxy;
      }
      const nObj = observe(obj);
      nObj.name;
      nObj.friendA.name;
      nObj.friendA.name = "ppp";
      nObj.name = "ahhh";
      nObj.aaaaaaaa; //不存在的属性也会被劫持

优点: 不存在的属性也会被做劫持