最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 聊聊Object.defineProperty和Proxy

    正文概述 掘金(明洁)   2021-02-26   561

    写在开头,我相信只要稍微是对vue源码有一定了解的人,都知道vue2.0是通过Object.defineProperty来实现数据的劫持的,而vue3.0换了以一种数据监听的方式proxy,毋庸置疑,proxy相比于Object.defineProperty肯定是有一定优势的,不然尤大大也不会花费力气重写,所以今天我们来聊一聊Object.definePropertyProxy

    Object.defineProperty的劣势

    • 无法实现对数组的监听。

    但是使用过vue2.0的人都知道,当数组发生改变的时候,视图也会发生改变,它是怎么实现的呢?下面为大家揭开它什么的面纱。最主要的原因是vue2.0它重写了Array.prototype的方法,当被监听数据的类型是数组是,改变它的原型。

    function updateView() {
      console.log("视图要更新了");
    }
    // 数组的原型
    const oldPrototype = Array.prototype;
    // 创建一个原型指向Array.prototype的空对象,数组的新原型对象
    const newPrototype = Object.create(Array.prototype);
    // 数组应该存在方法,下面只是一部分
    const arrayMethod = ["push", "pop", "shift", "unshift"];
    
    arrayMethod.forEach((methodName) => {
      newPrototype[methodName] = function () {
        oldPrototype[methodName].call(this, ...arguments);
        updateView();
      };
    });
    

    在上篇文章当中,数据劫持还存在一定的缺陷,没有对数组进行监听,现在我们既然知道了原理,接下来,看看具体的代码实现:

    function observer(data) {
      if (isBaseType(data)) return data;
      // 重写数组的原型对象
      if(isArray(data)) data.__proto__ = newPrototype
      Object.keys(data).forEach((key) => {
        defineReactive(data, key, data[key]);
      });
    }
    

    虽然这样能够实现数组的监听,但是相比于proxy来说,还是比较麻烦的。

    • 实现对象的深度监听,需要一次性递归到底。对于层级比较深的数据来说,计算量比较大。

    具体怎么实现对象的深度监听,可以参考我的上篇文章。

    • 无法监听新增属性/删除属性(但是vue2.0提供了另外的api,分别是Vue.set和Vue.delete)

    综合上述的和其他种种原因,尤大大决定更换数据监听的方式。

    Proxy

    proxy是es6新增的一个api,proxy在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截,所以我们在这一层拦截当中可以完成我们想完成的事情。

    下面我们来看看proxy的具体用法,首先要生成一个Proxy实例,如下:

    const proxy = new Proxy(target, handler);
    

    target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。继续看下面的代码:

    // 现在有个对象
    const target = {
       name: 'poetries',
     };
    const handler = {
       get: function(target, key, receive) {
         const result = Reflect.get(target, key,receive);
         console.log(`${key} 被读取`,result);
         return result;
       },
       set: function(target, key, value, receive) {
         const result = Reflect.set(target, key, value, receive);
         console.log(`${key} 被设置为 ${value}`);
         return result;
       },
       deleteProperty: function(target, key){
         const result = Reflect.deleteProperty(target, key);
         console.log(`${key}`被删除);
         return result;
       }
     }
    

    从上面的代码我们可以看出,当操作完成对象的某个属性之前,我们都可以任意执行我们的业务逻辑。接下来就是利用proxy代替Object.defineProperty来实现数据劫持。

    function observer(data) {
      if (isBaseType(data)) return data;
      const handler = {
         get: function(target, key, receive) {
           // 只处理自身上的属性(不包括原型)
           const ownKeys = Reflect.ownKeys(target);
           if(ownKeys.includes(key)){
              console.log(`${key},你已被监听`);
           }
           const result = Reflect.get(target, key,receive);
           console.log(`${key} 被读取`,result);
           return observer(result);
       },
       set: function(target, key, value, receive) {
         if(target[key] === value){
            // 如果前后两次的value相同,则直接跳过,不做处理
            return true;
         }
         const result = Reflect.set(target, key, value, receive);
         console.log(`${key} 被设置为 ${value}`);
         // 深度监听,和Object.defineProperty不同是,只有当使用这个对象才会去监听对象里面的属性。
         return result;
       },
       deleteProperty: function(target, key){
         const result = Reflect.deleteProperty(target, key);
         console.log(`${key}`被删除);
         return result;
       }
      }
      const observedData = new Proxy(data,handler);
      return observedData;
    }
    

    所以,proxy很好的规避了Object.defineProperty的问题。


    起源地下载网 » 聊聊Object.defineProperty和Proxy

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元