zoukankan      html  css  js  c++  java
  • 学习 vue2.0/3.0 中的proxy和Object.defineProperty 小记

      vue3.0将双向数据绑定的主要方法从Object.defineProperty舍弃,使用了proxy的方式通过观察者模式实现相关的数据变化监听,总的来说是一个很好地前进。今天简单的实验了一下相关的实现和不同情况下的使用输出。简单记录一下吧。同时说明代码中是使用数组的例子进行区分的。

      个人认为proxy的实现方式要比Object.defineProperty优雅很多,Object.defineProperty首先是指数据劫持,实际上proxy的运行是后置于Object.defineProperty,也就是说如果对同一个对象进行俩者同时使用的时候,要注意Object.defineProperty的各个参数是否会影响proxy内部的设置,例如configurable属性如果设置了不可修改,那么在proxy进行代理时,在get方法中最终改变了输出的内容,是会出现问题的。

       var data = {}
        Object.defineProperty(data, 'a', {
          value: 1,
          configurable: true,
        })
        let proxy = new Proxy(data, {
          get(obj, prop) {
            console.log('get');
            return 2;
          },
          set(obj, prop, val) {
            console.log('set');
            console.log(obj);
            obj[prop]= val;
            return true;
          }
        });
        console.log(proxy.a);

      如果此处的configurable不设置为true则会报错。除此之外Object.defineProperty另外的两个属性也有一些自己的使用方法在其中。使用的时候要注意。

      同时由上面的代码可以明显的看出proxy的方式对对象进行设置代理的时候,会比Object.defineProperty进行劫持的时候方便很多,因为Object.defineProperty需要对具体的某个属性进行设置,这就导致了我们需要遍历所有的对象内部的内容,之后对每个都进行劫持才可以达到想要的效果,而proxy仅仅对对象整体进行监控就好了。

      除此之外proxy也增加了对于数组的监控。

    var data = {
      dataarr: [1,2,3,4]
    };
    let proxy = new Proxy(data.dataarr, {
      get(obj, prop) {
        return obj[prop];
      },
      set(obj, prop, val) {
        console.log('set');
        obj[prop]= val;
        return true;
      }
    });
    proxy.push(1);
    console.log(data.dataarr); 
    // set
    // [1, 2, 3, 4, 1]

      此时在上面代码中,如果添加了对应的数组内容。proxy会提示数组发生了变化。同样的,使用诸如proxy[1] = 7等等都可以触发更改,而Object.defineProperty则不同,它并不能在修改数组内容时触发相应的更改。

    var data = {};
    var watch;
    Object.defineProperty(data, 'dataarr', {
      set(val) {
        console.log('set');
        watch = val;
        return true;
      },
      get() {
        console.log('get');
        return watch;
      }
    })
    data.dataarr = [1,2,3,4];
    data.dataarr.push(3);
    // set
    // get

      我们可以看到实际上第一个set是由你设置data.dataarr = [1,2,3,4]; 触发产生的。而push操作实际上仅仅是修改了data.dataarr的内容,并没有触发set。

      但是但是。proxy虽然很好用,但是它的性能其实很差。差到什么地步呢?假设我们按照如下代码检测。

    var _obj = {};
    var proxy = new Proxy(_obj, {
      set: (obj, prop, value) => { _obj[prop] = value; }
    });
    
    var defineProp = {};
    Object.defineProperty(defineProp, 'prop', {
      configurable: false,
      set: v => defineProp._v = v
    });
    
    //  上述为建立不同的对象
    
    obj.prop = 5;
    
    proxy.prop = 5;
    
    defineProp.prop = 5;
    
    // 为赋值语句。

      如果我们按照这样的逻辑进行赋值代码,最终实现的监测数据是这样的

    vanilla x 74,288,023 ops/sec ±0.78% (86 runs sampled)
    proxy x 3,625,152 ops/sec ±2.51% (86 runs sampled)
    defineProperty x 74,815,513 ops/sec ±0.80% (85 runs sampled)
    Fastest is defineProperty,vanilla

    ps:ops/sec为每秒执行次数,数字越大越好。

      可以看到速度会比defineProperty的方式整整慢了一倍多,如果当然还有其他的情况下的检测,如果有兴趣可以看https://thecodebarbarian.com/thoughts-on-es6-proxies-performance,一位大佬写的检测。但是这就像前面这篇文章结尾说的那样。实际上对于执行速度的慢并不能影响proxy的推行,就例如promise的执行效率实际上要比回调的方式慢好多,但是依旧无法阻挡它推行的脚步,而且据一些国内大佬的检测数据来看,在较新版本下的node运行promise已经比以前的速度要快了很多,也就是说其实技术的优化始终可以达到。我们要的首先都是要好,只要性能不会太限制使用就好。人们一起推进的力量是伟大的。总会优化到我们欣喜的模样。vue3.0或许是一个很好的契机。借助vue3.0的推行,proxy的未来相信会越来越好。

  • 相关阅读:
    JavaScript之正则表达式
    BOM之本地数据存储
    BOM之定时器
    BOM之window核心模块
    BOM简介
    DOM之元素定位
    DOM之事件
    DOM之节点操作
    DOM简介
    linux机制
  • 原文地址:https://www.cnblogs.com/acefeng/p/12222552.html
Copyright © 2011-2022 走看看