Vue3使用Proxy实现数据监听的原因分析

vue 数据双向绑定原理,而这个方法有缺点,并且不能实现数组和对象的部分监听情况;具体也可以看我之前写的一篇博客: 关于 Vue 不能 watch 数组 和 对象变化的解决方案,最新的 Proxy,相比 vue2 的 Object.defineProperty,能达到速度加倍、内存减半的成效。具体是怎么实现、以及对比旧的实现方法为啥能有速度加倍、内存减半的特性,下面我们来聊聊:

Vue 初始化过程

Vue 的初始化过程,分别有Observer、Compiler和Watcher,当我们 new Vue 的时候,会调用Observer,通过 Object.defineProperty 遍历 vue 对象的 data、computed 或者 props(如果是组件的话)的所有属性进行监听。同时通过Compiler解析模板指令,解析到属性后就 new 一个Watcher并绑定更新函数到 watcher 当中,Observer 和 Compiler 就通过属性来进行关联。

Object.defineProperty

来个简单的 Object.defineProperty例子

class Observer {
    constructor(data) {
      // 遍历参数 data 的属性,给添加到 this 上
      for (let key of Object.keys(data)) {
        if (typeof data[key] === "object") {
          data[key] = new Observer(data[key]);
        }
        Object.defineProperty(this, key, {
          enumerable: true,
          configurable: true,
          get() {
            console.log("你访问了" + key);//你访问了age
            return data[key];//20
          },
          set(newVal) {
            console.log("你设置了" + key); //你设置了age
            console.log("新的" + key + "=" + newVal); //新的age=20
            if (newVal === data[key]) {
              return;
            }
            data[key] = newVal;
          }
        });
      }
    }
  }const obj = {
    name: "app",
    age: "18",
    a: {
      b: 1,
      c: 2,
    }
  };const app = new Observer(obj);app.age = 20;console.log(app.age);app.newPropKey = "新属性";console.log(app.newPropKey);    //新属性

从上面可以知道:Object.defineProperty 需要遍历所有的属性,这就造成了如果 vue 对象的data/computed/props 中的数据规模庞大,那么遍历起来就会慢很多.同理,如果 vue 对象的 data/computed/props 中的数据规模庞大,那么 Object.defineProperty 需要监听所有的属性的变化,那么占用内存就会很大。

Proxy

我们来看看proxy

Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)

可以理解为在对象之前设置一个”拦截“,当监听的对象被访问的时候,都必须经过这层拦截。可以在这拦截中对原对象处理,返回需要的数据格式,也就是无论访问对象的什么属性,之前定义的或是新增的属性,都会走到拦截中进行处理。这就解决了之前所无法监听的问题。

const obj = {
  name: "krry",
  age: 24,
  others: {
    mobile: "mi10",
    watch: "mi4",
  },};const p = new Proxy(obj, {
  get(target, key, receiver) {
    console.log("查看的属性为:" + key);
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    console.log("设置的属性为:" + key);
    console.log("新的属性:" + key, "值为:" + value);
    Reflect.set(target, key, value, receiver);
  },});p.age = 22;console.log(p.age); p.single = "NO";console.log(p.single);p.others.shoe = "boost";console.log(p.others.shoe);输出结果为:设置的属性为:age
新的属性:age 值为:22查看的属性为:age22

设置的属性为:single
新的属性:single 值为:NO查看的属性为:singleNO 查看的属性为:others
查看的属性为:others
boost

由上可知,新增或编辑属性,并不需要重新添加响应式处理,都能监听的到,因为 Proxy 是对对象的操作,只要你访问对象,就会走到 Proxy 的逻辑中。Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers的方法相同。Reflect不是一个函数对象,因此它是不可构造的,区别Proxy 和 Object.defineProperty 的使用方法看似很相似,其实 Proxy 是在更高维度上去拦截属性的。

Object.definePropertyVue2 中,对于给定的 data:如 { count: 1 },是需要根据具体的 key 也就是 count,去对 get 和 set 进行拦截,也就是:

Object.defineProperty(data, 'count', {
  get() {},
  set() {},})

必须预先知道要拦截的 key 是什么,这也就是为什么 Vue2 里对于对象上的新增属性无能为力,所以 Vue 初始化的过程中需要遍历 data 来挟持数据变化,造成速度变慢,内存变大的原因。

Proxy 而 Vue3 所使用的 Proxy,则是这样拦截的:

new Proxy(data, {
  get(key) { },
  set(key, value) { },})

可以看到,proxy 不需要关心具体的 key,它去拦截的是修改 data 上的任意 key和读取 data 上的任意 key

所以,不管是已有的 key 还是新增的 key,都会监听到。

到此这篇关于Vue3使用Proxy实现数据监听的原因分析的文章就介绍到这了,更多相关Vue3为什么使用Proxy实现数据监听内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue3使用Proxy实现数据监听的原因分析

    vue 数据双向绑定原理,而这个方法有缺点,并且不能实现数组和对象的部分监听情况;具体也可以看我之前写的一篇博客: 关于 Vue 不能 watch 数组 和 对象变化的解决方案,最新的 Proxy,相比 vue2 的 Object.defineProperty,能达到速度加倍.内存减半的成效.具体是怎么实现.以及对比旧的实现方法为啥能有速度加倍.内存减半的特性,下面我们来聊聊: Vue 初始化过程 Vue 的初始化过程,分别有Observer.Compiler和Watcher,当我们 new V

  • 为什么Vue3.0使用Proxy实现数据监听(defineProperty表示不背这个锅)

    导 读 vue3.0中,响应式数据部分弃用了 Object.defineProperty ,使用 Proxy 来代替它.本文将主要通过以下方面来分析为什么vue选择弃用 Object.defineProperty . Object.defineProperty 真的无法监测数组下标的变化吗? 分析vue2.x中对数组 Observe 部分源码 对比 Object.defineProperty 和 Proxy 一.无法监控到数组下标的变化? 在一些技术博客上看到过这样一种说法,认为 Object.

  • 浅析Proxy可以优化vue的数据监听机制问题及实现思路

    我们首先来看vue2.x中的实现,为简单起见,我们这里不考虑多级嵌套,也不考虑数组 vue2.x中的实现 其本质是new Watcher(data, key, callback)的方式,而在调用之前是先将data中的所有属性转化成可监听的对象, 其主要就是利用Object.defineProperty,. class Watcher{ constructor(data, key, cb){ } } //转换成可监听对象 function observe(data){ new Observer(d

  • vue数据监听解析Object.defineProperty与Proxy区别

    目录 前言 Object.defineProperty 与 Proxy 的区别 在使用上的差异 总结与思考 前言 总能深深感觉到自己能力有限,写这篇文章的目的纯粹是因为发现在实际工作中,和一些小伙伴交流时发现,虽然有些小伙伴大概知道 vue2 与 vue3 的区别,但并没有去进一步思考一些深一点的东西.尽管能力有限,但想着自己在起步时候的艰难,就想着分享一下自己的一些看法,虽然不一定有多深入,但能引起大家的一些思考也是好的. Object.defineProperty 与 Proxy 的区别 其

  • vue3怎么数据监听watch/watchEffect

    目录 watch()函数 watchEffect()函数 watch 与 watchEffect之间的联系与区别 我们都知道监听器的作用是在每次响应式状态发生变化时触发,在组合式 API 中,我们可以使用 watch()函数和watchEffect()函数, 当你更改了响应式状态,它可能会同时触发 Vue 组件更新和侦听器回调. 默认情况下,用户创建的侦听器回调,都会在 Vue 组件更新之前被调用.这意味着你在侦听器回调中访问的 DOM 将是被 Vue 更新之前的状态. 那么,我们来看一下,怎么

  • 浅谈vue实现数据监听的函数 Object.defineProperty

    在 ES5中新增了不少新的API, 例如  新增了 Object.xxx相关的方法,其中有一个定义属性相关的 Object.defineProperty 这个方法(还有Object.defineProperties)这个方法是 vue框架实现数据监听的核心方法,它的定义如下: Object.defineProperty([Object] obj, [String] propname, [Object] desp ) @param  obj  要配置属性的某个对象 @param propname

  • Vue中的数据监听和数据交互案例解析

    现在我们来看一下vue中的数据监听事件$watch, js代码: new Vue({ el:"#div", data:{ arr:[1,2,3] } }).$watch("arr",function () { alert("数据改变了") }) html代码: <div id="div"> <input type="button" value="改变" @click=&

  • 如何用JS实现简单的数据监听

    概述 主要是用Object.defineProperty实现类似vue的数据绑定. 第一步 const data = { name: "tom", age: 14 } Object.defineProperty(data, "name", { get(){ return "name被读取了" }, set(val){ console.log('我被赋值了',val) } }) //将此代码放到浏览器控制台查看效果 console.log(data

  • react实现数据监听方式

    目录 react 数据监听 react事件监听三种写法 方式一 方式二 方式三 react 数据监听 监听组件传递的值:  componentWillReceiveProps(newProps)  {      参数为给组件传递的参数  } 监听组件内部状态的变化: componentDidUpdate(prevProps,prevState){     参数分别为改变之前的数据状态对象     if(prevState.属性名!=this.state.属性名)     {         ..

  • Vue数据监听方法watch的使用

    watch本身很容易理解, watch负责将视图中的数据与某个函数关联起来 当Vue视图中的数据变化时, 关联的函数会被执行 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>监听方法watch的使用</title> <script src="https://cdn.bootcss.com/

随机推荐