【ES6】浅谈Vue3为什么使用Proxy取代defineProperty

  • Post author:
  • Post category:vue





前言

友友们大家好,vue3推出后大家有没有去看呢?博主是个性子急的人,哪能禁得住这诱惑。

经过博主粗略的阅读,我感觉vue3最大的变化之一便是使用Proxy取代defineProperty去实现数据劫持。

让我们想一想,为什么会这样呢?

不知道大家有没有遇到过,在项目中改变数组或给对象添加属性,视图并没有相应式的更新。这其实就是defineProperty的一个缺陷,下面我将会给大家详细介绍Proxy和取代defineProperty的原因。



一、Proxy是什么?

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

const proxy = new Proxy(target, handler);

Proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。

若handler参数为空对象,则返回原属性值。

例如:

const proxy = new Proxy({}, {
// get方法的两个参数分别是目标对象和所要访问的属性
  get: function(target, propKey) {
    return 35;
  }
});

proxy.time // 35
proxy.name // 35
proxy.title // 35

上述代码中,对target(本例中的空对象)进行了拦截,由于拦截函数总是返回35,所以访问的所有属性都返回35。

下面介绍handler参数里的set和get方法:



get()

get方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。

例如:

const obj = { a: 1 };
      const proxy = new Proxy(obj, {
        get: function (target, propKey) {
          if (target[propKey]) {
            return target[propKey];
          } else {
            return "我没有";
          }
        },
      });

      console.log(proxy.a);
      console.log(proxy.b);

在这里插入图片描述

get方法也可以继承,例如:

const obj = { a: 1 };
      const proxy = new Proxy(obj, {
        get: function (target, propKey) {
          if (target[propKey]) {
            return target[propKey];
          } else {
            return "我没有";
          }
        },
      });
      const obj1 = Object.create(proxy);
      console.log(obj1.a);
      console.log(obj1.b);

在这里插入图片描述

当obj1没有属性时,就会顺着原型链查找到proxy



set()

set方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。

通俗一点说就是get是在读取数据做处理,set是在赋值做处理。

例如:

const obj = { a: 1 };
      const proxy = new Proxy(obj, {
        set: function (obj, key, value) {
          if (key === "age") {
            if (value <= 20) {
              console.log("年轻人");
            } else {
              console.log("老人");
            }
          }
        },
      });
      proxy.age = 17;

在这里插入图片描述

我们可以利用set来进行属性赋值的校验,比如年龄只能到0-100之间的操作。

以上我们只简单介绍proxy的常用方法,如果有兴趣的同学,可以看一看阮一峰的es6标准入门学习一下哦



二、Vue双向绑定实现原理

大家都知道,vue2.x的双向绑定原理是利用数据劫持结合发布订阅模式实现的。

可以简化为下面几步:

  1. observer(观察者)、watcher(订阅对象)、notify(通知订阅对象的通报)、compiler(解析器)
  2. observer用来对初始数据通过Object.defineProperty添加setter和getter,当取数据(即调用get)的时候添加订阅对象(watcher)到数组里
  3. 当给数据赋值(即调用set)的时候就能知道数据的变化,此时调用发布订阅中心的notify,从而遍历当前这个数据的订阅数组,执行里面所有的watcher,通知变化。
  4. compiler负责data编译到dom中



三、Vue3为什么使用Proxy



defineProperty缺陷

  • 不能监听数组变化
  • 只能劫持对象的属性(给对象添加属性vue无法检测到)

vue是怎么解决这个问题呢,也就是我们在vue2.x里该怎么去解决这个问题呢?

这个部分可以去看我的另一篇文章哦,传送门:

解决vue中改变数组视图不更新



Proxy的好处

  • proxy可以直接监听数组的变化
  • proxy可以监听对象而非属性.它在目标对象之前架设一层“拦截”,因此提供了一种机制,可以对外界的访问进行过滤和改写。proxy直接劫持一个对象,并且会返回一个新对象。

由上可以看出,vue3使用proxy的原因:

  • proxy解决了defineProperty的缺陷。
  • proxy会被持续的性能优化

但是proxy由于是es6的方法,所以也会存在着兼容性的问题



总结

本文只是简单介绍了为什么vue使用proxy的原因,如果有小伙伴感兴趣可以去研究研究哦。



版权声明:本文为hhhhhhhssss原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。