• 响应式数据


    一,概述

    响应式,个人理解就是数据a变更,会自动更新所有用到a的地方。即它变更后会自动更新所有依赖于它的地方

    具体在vue的代码中有这么几个地方。

    1,html中渲染展示绑定的数据
    2,watch和conputed中的依赖项
    
    • 1
    • 2

    那如何实现自动更新?

    首先需要能捕获它的变更,这样才可以在它变更的时候,去更新和它相关的地方。

    现有的捕获数据变更的方式有以下三种:

    1,利用Object.definePropery数据劫持。
    2,利用Proxy数据代理。
    3,利用对象的 get 和 set 函数
    
    • 1
    • 2
    • 3

    二,非响应式数据

    最开始的时候,我们的代码时按照顺序执行的。

    let single = 1;
    let double = single * 2;
    console.log(double);
    single = 2;
    console.log(double);//这时候double还是2
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到,代码按照顺序执行,single发生变化后,并不会更新依赖于它的double,所以这个single就不是一个响应式的数据。

    三,基于Object.defineProperty实现

    vue2的数据响应就是利用它实现的。

    const handleClick = function () {
      obj.single++;
      console.log(obj.single, double);
    };
    const handleDouble = val => val * 2;
    let obj = {};
    let single = 2;
    let double = handleDouble(single);
    Object.defineProperty(obj, 'single', {
      get() {
        return single;
      },
      set(val) {
        single = val;
        docble = handleDouble(val); //依赖于它的值需要更新一次
      }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    这里用obj这个对象,使用Object.defineProperty拦截了对其属性single的访问和修改,而修改时,我们就能在set函数中捕获对它的修改,从而去执行跟新相关数据的方法。(这里只有double依赖于它变化,所以执行更新double的方法。)

    使用这个方法有一些缺点:

    1,只有监听的属性才能被劫持。在vue2中体现出来就是一开始数据就要写在data中,要监听新增的属性需要用额外的api:this.$set。
    2,删除属性时,不会被监听到。比如删除 obj.single 属性,set 函数就不会执行,double 还是之前的数值。体现在Vue 2 中,我们需要 $delete 一个专门的函数去删除数据。
    
    • 1
    • 2

    四,基于Proxy实现

    Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且我们也能通过 deleteProperty 实现对删除操作的代理。

    vue3中的reactive就是采用的这种方式。

    let handleDouble = n => n * 2;
    let obj = {
      single: 1
    };
    let double = handleDouble(obj.single);
    let proxy = new Proxy(obj, {
      get: function (target, prop) {
        return target[prop];
      },
      set: function (target, prop, value) {
        target[prop] = value;
        if (prop === 'single') {
          double = handleDouble(value);
        }
        return true;
      }
    });
    const handleClick = function () {
      proxy.single++;
      console.log(proxy.single, double);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    这里使用proxy来代理obj这个对象,当我们修改proxy.single的时候,会被set函数捕获,从而修改obj.single的值。

    值得注意的是,peoxy捕获的是该对象内 所有的变更。所以需要根据prop来判断变更的是哪个属性,然后针对这个属性完成它相关项的更新(handleDouble(value))。

    五,基于对象的 get 和 set 函数

    这种响应式的实现方式,只能拦截某一个属性的修改。vue3中的ref就是采用的这种方式。

    let handleDouble = n => n * 2;
    let ref = function (val) {
      let single = val;
      return {
        get value() {
          return single;
        },
        set value(val) {
          single = val;
          double = handleDouble(val);
        }
      };
    };
    let singleTest = ref(1);
    let double = handleDouble(singleTest.value);
    const handleClick = function () {
      singleTest.value++;
      console.log(singleTest.value, double);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    当修改singleTest的值的时候,set函数会捕获这种改变,从而更新double的值。

    这就是在vue3中为啥访问ref声明的参数时,需要加.value的原因。

    六,总结

    实际上,所谓的响应式数据,就是做到了以下两个事情。

    1,能够捕获该数据的变更。
    2,该数据变更后能自动调用更新依赖于它的相关页面/数据
    
    • 1
    • 2
  • 相关阅读:
    如何批量图片重命名不同名字?
    初识ES6
    C++学习之旅 第一章 C++预备知识
    计算机系统的基本概念
    Spring Boot获取客户端的IP地址
    【前端笔试】知识点总结
    五年制专转本的作文评分标准及拿分方法
    C++学习笔记(面向对象部分开始6500字复习总结)
    小程序商城的运营推广技巧(二)
    I/O多路转接-epoll
  • 原文地址:https://blog.csdn.net/weixin_42349568/article/details/126708509