IT培训-高端面授IT培训机构
云和教育:云和数据集团高端IT职业教育品牌 全国咨询热线:0371-67988003
课程 请选择课程
    校区 请选择校区
      • 华为
        授权培训中心
      • 腾讯云
        一级认证培训中心
      • 百度营销大学
        豫陕深授权运营中心
      • Oracle甲骨文
        OAEP中心
      • Microsoft Azure
        微软云合作伙伴
      • Unity公司
        战略合作伙伴
      • 普华基础软件
        战略合作伙伴
      • 新开普(股票代码300248)
        旗下丹诚开普投资
      • 中国互联网百强企业锐之旗
        旗下锐旗资本投资

      H5大咖分享:Vue3为何使用Proxy实现数据监听

      • 发布时间:
        2020-08-13
      • 版权所有:
        云和教育
      • 分享:
      郑州h5培训教程:Vue3为何使用Proxy实现数据监听前言
      vue3响应式数据放弃了Object.define Property,而使用Proxy来代替它。我们知道,在 vue2 中,实现数据监听是使用Object.defineProperty –> 实现方法可看:vue 数据双向绑定原理。而这个方法有缺点,并且不能实现数组和对象的部分监听情况;具体也可以看我之前写的一篇博客:关于 Vue 不能 watch 数组 和 对象变化的解决方案。最新的 Proxy,相比 vue2 的 Object.define Property,能达到速度加倍、内存减半的成效。具体是怎么实现、以及对比旧的实现方法为啥能有速度加倍、内存减半的特性。

      Vue 初始化过程
      Vue 的初始化过程,分别有ObserverCompilerWatcher。

      当我们 new Vue 的时候,会调用Observer,通过 Object.defineProperty 遍历 vue 对象的 data、computed 或者 props(如果是组件的话)的所有属性进行监听。同时通过Compiler解析模板指令,解析到属性后就 new 一个Watcher并绑定更新函数到 watcher 当中,Observer 和 Compiler 就通过属性来进行关联。
      如上,当 Observer 中的 setter 检测到属性值改变的时候,就调用属性对应的所有 watcher 调用更新函数,从而更新到属性对应的 dom。
      Object.defineProperty
      来个简单的 Object.defineProperty 例子
      输出如下:
      从上面可以知道:
      1. Object.defineProperty 需要遍历所有的属性,这就造成了如果 vue 对象的 data/computed/props 中的数据规模庞大,那么遍历起来就会慢很多
      2. 同理,如果 vue 对象的 data/computed/props 中的数据规模庞大,那么 Object.defineProperty 需要监听所有的属性的变化,那么占用内存就会很大
      Proxy
      再来看看 Proxy
      Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)
      可以理解为在对象之前设置一个“拦截”,当监听的对象被访问的时候,都必须经过这层拦截。可以在这拦截中对原对象处理,返回需要的数据格式。
      也就是无论访问对象的什么属性,之前定义的或是新增的属性,都会走到拦截中进行处理。这就解决了之前所无法监听的问题。
      官方例子:
      const p = new Proxy(target, handler)
      参数
      • target:要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
      • handler:一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为
      来个实际 Proxy 例子
      输出如下:
      由上可知,新增或编辑属性,并不需要重新添加响应式处理,都能监听的到。因为 Proxy 是对对象的操作,只要你访问对象,就会走到 Proxy 的逻辑中。
      Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的

      区别

      Proxy 和 Object.defineProperty 的使用方法看似很相似,其实 Proxy 是在更高维度上去拦截属性的。
      Object.defineProperty
      Vue2 中,对于给定的 data:如 { count: 1 },是需要根据具体的 key 也就是 count,去对 get 和 set 进行拦截,也就是:
      必须预先知道要拦截的 key 是什么,这也就是为什么 Vue2 里对于对象上的新增属性无能为力,所以 Vue 初始化的过程中需要遍历 data 来挟持数据变化,造成速度变慢,内存变大的原因。
      Proxy
      而 Vue3 所使用的 Proxy,则是这样拦截的:
      可以看到,proxy 不需要关心具体的 key,它去拦截的是 修改 data 上的任意 key 和 读取 data 上的任意 key。

      所以,不管是已有的 key 还是新增的 key,都会监听到。但是 Proxy 更加强大的地方还在于 Proxy 除了 get 和 set,还可以拦截更多的操作符,具体可看 MDN。

      兼容性

      Proxy 对 IE 不友好,vue3 在检测到使用 IE 的情况下(包括 IE11),会自动降级为 Object.defineProperty 的数据监听系统。
      文/云和数据H5高级工程师,郑州H5前端开发培训就来云和数据!