Vue2和Vue3的双向数据绑定原理分析

 更新时间:2025年02月06日 09:47:43   作者:清风 与我  
Vue2.x通过Object.defineProperty()实现响应式系统,但存在一些限制,如不能检测新增和删除的属性、深层嵌套对象性能开销大等,Vue3.0引入Proxy,可以更高效地拦截对象操作,解决这些问题

vue2.x 是如何实现响应式系统的

当你把一个普通的 js 对象传入 vue 实例作为 data 选项,vue 将遍历此对象的所有prototype(属性),并使用 object.defineProperty(),将这些 prototype(属性),全部转换为 getter / setter,在 getter 中收集数据依赖,在 setter 中监听数据变化,一旦数据发生改变,在通知订阅者。

每个组件实例,都对应一个 watcher 实例,它会在组件渲染的过程把 “接触” 过的数据 prototype(属性)记录为依赖,之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染;

defineProperty 的痛点

  1. 它无法发现对象新增和被删除的属性,当你给一个对象添加一个新的属性,这个新增的属性没有添加到 vue 的数据更新侦查机制里;

Vue.set() 可以让 vue 知道你新增了一个属性,其实 Vue.set 可以让 Vue 知道新增了一个属性。其实 set() 内部也是通过调用 defineProperty() 来实现;

  1. 当你利用索引直接设置一个数组(new Array(4))或者修改数组的长度时,Vue 不能检测到数组的变动;
  2. 当对象嵌套的层数特别深(多层嵌套)的时候,递归遍历带来的性能开销就会比较大;

Object.defineProperty 代码的使用

mounted() {
    // 先定义好一套规则
    class Observer {
      constructor(data) {
        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("You visited" + key);
              return data[key];
            },
            set(NewValue) {
              console.log("You set" + key);
              console.log("New Value" + NewValue);
              if (NewValue === data[key]) {
                return;
              }
              data[key] = NewValue;
            },
          });
        }
      }
    }
    let obj = {
      name: "app",
      age: 18,
      a: {
        b: 1,
        c: {
          d: 1,
        },
      },
    };
    let app = new Observer(obj);
    console.log(app);
    app.age = 20;
    app.newProperty = "new attrs";
    console.log(app);
  },

结果:

Proxy 方法的理解

Proxy 在 vue3.0 中上位

可以解决 defineProperty 的痛点,因为本质的原因在于 Proxy 是内置了拦截器对象。所有的外部访问都得先经过这一层拦截,不管是先前定义好的,还是新增的属性,又或者是深层的嵌套属性,访问时都会被拦截;

Reflect.set()方法用于设置对象属性的值,1:目标对象:2:改变参数的名称:3:改变参数的值:4:值是this如果遇到设置器,将提供给目标调用。

此方法返回一个布尔值,该值指示该属性是否已成功设置。

Proxy 代码的使用

mounted() {
    const obj = {
      name: "app",
      age: 19,
      a: {
        b: 1,
        c: 2,
      },
    };
    const p = new Proxy(obj, {
      get(target, propKey, receiver) {
        console.log("Your visited:" + propKey);
        // Reflect.set()方法用于设置对象属性的值:1:目标对象:2:改变参数的名称:3:改变参数的值
        // 此方法返回一个布尔值,该值指示该属性是否已成功设置。
        return Reflect.set(target, propKey, receiver);
      },
      set(target, propKey, value, receiver) {
        console.log("You set:" + propKey);
        console.log("New value:" + value);
        // Reflect.set()方法用于设置对象属性的值,1:目标对象:2:改变参数的名称:3:改变参数的值:4:值是this如果遇到设置器,将提供给目标调用。
        // 此方法返回一个布尔值,该值指示该属性是否已成功设置。
        return Reflect.set(target, propKey, value, receiver);
      },
    });
    p.age = "20";
    console.log(p);
    p.newProperty = "New attribute";
    console.log(p);
  },

结果:

总结

  1. proxy 是用来操作对象并且扩展对象能到,而 Object.defineProperty() 只是单纯的操作对象的属性;
  2. Vue2.X 是用 Object.defineProperty() 实现数据响应的,但是受限于 defineProperty() 的实现,必须递归遍历至对象的最底层;
  3. vue3.0 用 Proxy 来拦截对象,不管对目标执行任何操作,都会先通过 Proxy 的处理逻辑;
  4. 除了 Vue3.0,还有其他的库也在使用 Proxy。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vue 对axios get pust put delete封装的实例代码

    vue 对axios get pust put delete封装的实例代码

    在本篇文章里我们给各位整理的是一篇关于vue 对axios get pust put delete封装的实例代码内容,有需要的朋友们可以参考下。
    2020-01-01
  • 基于Vuejs实现购物车功能

    基于Vuejs实现购物车功能

    这篇文章主要为大家详细介绍了基于Vuejs实现购物车功能的相关资料,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • 解决vuejs 使用value in list 循环遍历数组出现警告的问题

    解决vuejs 使用value in list 循环遍历数组出现警告的问题

    今天小编就为大家分享一篇解决vuejs 使用value in list 循环遍历数组出现警告的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • Vue数据变化后页面更新详细介绍

    Vue数据变化后页面更新详细介绍

    这篇文章主要介绍了Vue在数据发生变化后是如何更新页面的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-10-10
  • vue项目多租户环境变量的设置

    vue项目多租户环境变量的设置

    本文主要介绍了vue项目多租户环境变量的设置,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • vue cookie和本地存储的使用详解

    vue cookie和本地存储的使用详解

    在Vue中,可以使用多种方式来处理cookie和本地存储,不同的方法还有不同的特点和适用场景,本文主要介绍了这些方法的对比和使用场景,希望对大家有所帮助
    2023-08-08
  • vue+vant实现商品列表批量倒计时功能

    vue+vant实现商品列表批量倒计时功能

    这篇文章主要介绍了vue+vant实现商品列表批量倒计时功能,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01
  • vue 界面刷新数据被清除 localStorage的使用详解

    vue 界面刷新数据被清除 localStorage的使用详解

    今天小编就为大家分享一篇vue 界面刷新数据被清除 localStorage的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • select的change方法传递多个参数的方法详解

    select的change方法传递多个参数的方法详解

    element-ui中的select,checkbox等组件的change方法的回调函数只有当前选择的val,如果想再传入自定义参数怎么办,本文给大家分享select的change方法如何传递多个参数,感兴趣的朋友一起看看吧
    2024-02-02
  • Vue 框架之动态绑定 css 样式实例分析

    Vue 框架之动态绑定 css 样式实例分析

    这篇文章主要介绍了Vue 框架之动态绑定 css 样式的方法,本文通过分享小实例给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-11-11

最新评论