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

news/2024/7/11 1:50:34 标签: es6, vue, proxy

文章目录

  • 前言
  • 一、Proxy是什么?
    • get()
    • set()
  • 二、Vue双向绑定实现原理
  • 三、Vue3为什么使用Proxy
    • defineProperty缺陷
    • Proxy的好处
  • 总结


前言

友友们大家好,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的原因,如果有小伙伴感兴趣可以去研究研究哦。


http://www.niftyadmin.cn/n/861672.html

相关文章

【ES6】浅谈Generator和yield

文章目录前言一、async await实现二、Generator实现三、Generator函数1、什么是Generator2.Generator的特点3.Generator的执行四、yield表达式1、什么是yield2、yield注意点五、Iterator对象五、next方法的参数总结前言 问题发生在一个下午&#xff0c;当我正在实现Promise.al…

常见css居中问题

文章目录前言一、水平居中已知宽度未知宽度二、垂直居中已知高度未知高度三、垂直水平居中总结前言 居中是我们项目开发中最常用到样式&#xff0c;可以说&#xff0c;作为一名合格的前端&#xff0c;各种情况下的居中应该是得心应手的&#xff0c;接下来让我们看看有哪些方式…

【JS编译原理】V8执行JavaScript代码过程

文章目录前言一、编译器和解释器二、V8执行JavaScript代码过程1.生成AST&#xff08;抽象语法树&#xff09;2.生成字节码3.生成机器码总结前言 相信大家对Babel已经不陌生了&#xff0c;Babel充斥在我们代码中的每个角落。比如&#xff1a;jsx转化成js&#xff0c;es6转化成e…

【React Hooks优化】减少重复渲染

文章目录前言一、为什么要进行优化&#xff1f;React的默认渲染行为二、使用memo/useMemo缓存组件1.memo2.useMemo2.useCallback总结前言 事情发生在一个下午&#xff0c;我需要用React hooks写一个定时器&#xff0c;因为useEffect每次执行都会使组件重新渲染一次&#xff0c…

【前端怪谈】两个行内块元素之间的间距问题

文章目录前言一、问题描述二、解决方式1.使用浮动2.清除行内块元素之间的空格和换行符3.父元素设置font-size:03.父元素设置word-spacing总结前言 相信行内块元素,也就是display:inline-block的元素大家并不少见,不知道大家有没有发现一个问题,就是当两个行内块元素在同一行并…

【前端怪谈】js中为什么0.1+0.2 !== 0.3

文章目录前言一、问题原因二、解决办法三、大数相加1、BigInt2、大数相加总结前言 下面大家先来看一下这行诡异的代码&#xff0c;猜猜会输出什么 console.log(0.1 0.2);是不是和所想的不太一样&#xff1f;下面我们来探索一下为什么它会这样吧。 一、问题原因 在计算机中…

【前端优化】超详细!带你体验常用的前端优化手段

文章目录前言一、图片懒加载原因判断是否进入可视区方案一: clientHeight、scrollTop 和 offsetTop方案二&#xff1a;getBoundingClientRect二、防抖与节流三、路由和组件懒加载原因使用实例路由懒加载:组件懒加载四、图片预加载原因五、使用前端缓存强缓存协商缓存六、减少回…

【前端怪谈】为什么要用setTimeout模拟setInterval

文章目录前言一、setInterval存在的问题1.问题复现2.问题分析二、setInterval缺点及setTimeout1.setInterval缺点2.为什么setTimeout能取代setTimeout实现setInterval总结前言 大家都知道&#xff0c;setTimeout是延迟执行函数&#xff0c;而setInterval就像一个定时器&#x…