• 19_Vue如何监测到对象类型数据发生改变的?


    数据更新

    关于监视

    • 我们之前讲过,我们在data当中配置的属性,最终会挂载在vue实例身上,而data这个配置项,最终也会在vue身上成为一个新的属性 == _data
      • image-20221029174302808
    • 当我们在页面DOM当中,去使用data当中的属性的时候,属性值发生变化,页面是不是会自动更新? 为什么会这样?
    • 你可以理解为 Vue底层默认有一个监视器,负责监视这些属性的变化
    • watchcomputed不同,这个监视是全局的,watch与computed是针对单独的,或者一些属性

    不过目前可以说一句,watch与vue底层监视,用的是一套类似的逻辑

    检测数据的原理

    这个概念是非常重要的,所以这节课是不能跳过的,否则有一天会为这个行为买单(谢谢,已经买过了)

    我们先来做个需求吧,这个需求不演示不行

    1. 你写一段代码,这个代码你需要修改data当中的数据
    2. 修改数据的行为,不能被vue检测到,也就是卡bug。
    3. 请你实现这个功能

    准备工作

    这是我的html设计,ul 当中的li标签渲染data当中persons这个数组的数据

    image-20221101164407586

    image-20221101164444632

    button按钮呢,设置了一个点击事件,这个点击事件用来单独修改 马冬梅这个对象的信息

    image-20221101164505759

    测试结果

    可以看到,在这种赋值的情况下,我们成功的对 马冬梅 进行了修改数据

    并且在vue当中也能检测到

    11-1-2

    卡bug,引出问题

    既然是 对马冬梅进行修改,我们换一种方式来对他进行修改

    11-1-3

    为什么这次数据修改不成功了,这是为什么?

    总结

    • 当我点击这个按钮的时候,在内存当中,persons[0]的数据确实发生改变了
    • 但是,这次修改并没有被vue所检测到
    • 至于控制台的数据到底修补修改,取决于你什么时候打开开发者工具

    检测原理

    image-20221101165614093

    vue是如何检测对象数据改变的

    • 我们先回顾一下关于vue的数据监测,详细博文
    • 我现在data这里有一个属性name和属性persons
      • image-20221101165925946
    • 打开控制台,在vue实例身上也有这俩属性
      • image-20221101170017797
    • 我们都知道,为什么这俩data当中属性会出现在vue实例身上,是因为做了数据代理
    • 在vue身上有个_data,这个下划线data当中包含着我们上图配置的data的所有数据,并且还对这个配置项data做了加工
      • image-20221101170237817
    • 因为如果只是 将 data的值,赋给_data,那么二者的内容应该是相等的才是
    • 但是现在显然不是,说明这里做了加工
    • 为啥他要加工?
      • 它加工了就可以做响应式了

    关于definedproperty

    • 之前说过,vue的数据代理definedProperty 这个API有关
    • 那么其内部是如何进行数据代理的呢?
    • 如果不使用 vue框架,我们能实现数据代理吗?
    • 我们来测试一下

    错误测试

    • 按照正常的理解,如果我们需要对age这个属性进行数据代理
    • 让页面能够检测到数据的改变,那么就需要使用这个接口(defined......)
    • 那么这个接口的调用,需要如下几个配置
      • 要给谁添加属性
      • 属性名是什么
      • 配置项(getter和setter)
    • 那么对getter而言,如果该属性被访问到了,那么就需要返回该属性的值
      • image-20221102101919433
    • 对setter而言,当属性值,发生修改,那么将接收到的修改的属性值,重新赋值给该属性

    image-20221102101738131

    我们虽然添加的是age,但是这里的意思是将原有属性age覆盖掉,使用这个新的age

    我们来看下测试结果

    11-2-1

    出现bug的原因

    • 其实这个问题很好理解,我们看下错误原因
      • image-20221102102329508
    • 这是一个 无限递归产生的bug,该方法一直无限的被调用,从而产生了这个错误
    • 为什么呢?
    • 我们仔细看下这段代码
      1. image-20221102102652200
      2. 当,age属性被访问的时候,会调用get函数
      3. 调用get函数,会返回age
      4. 返回的过程当中,age是不是又被访问了
      5. 从而产生死循环,无限递归
    • 为什么无法修改属性呢?也是这个道理

    所以,vue底层的数据代理,或者说数据加工没有我们想的这么简单,那么人家是怎么实现的呢

    Observer

    • 在vue当中,有个接口叫做Observer,这个接口用来监视页面数据发生的变化
    • 不过他底层是如何进行监听的呢
    • 我们写不到底层那么详细,只写主要的部分

    准备工作

    1、首先我们准备一个data,这里面存放了两个属性,name和age

    image-20221102112252052

    2、我们创建一个function ==> Observer

    image-20221102112336622

    然后实例化这个 Observer,js当中,function是可以当做构造函数使用的

    image-20221102112446513

    该函数需要一个属性,从参数名可以看出,这是一个对象属性

    3、现在我们就来配置这个对象,首先我们需要获取到 data这个对象当中的所有key值

    image-20221102112642593

    4、对这个数组,进行循环

    image-20221102112734575

    5、在迭代的过程当中,使用definedProperty进行数据代理

    image-20221102112845830

    参数解析,为什么这里,添加数据的对象(参数1) 是 this

    1. 使用this,那么就是给 this所指向的对象 ==> Observer;也就是我们刚刚实例化出来的对象
      • image-20221102113338407
    2. 给它添加属性(property参数
    3. 那么接下来我们就在 参数三 当中配置get和set了

    6、get和set

    image-20221102113208304

    数组当中是可以用字符串来获取元素值的(很少)

    完整代码

    // 这有一个对象,对象有两个属性
        let data = {
            name: "waves",
            age: 0
        }
    
        // 实例化一个监视器对象
        let observer = new Observer(data);
    
        // 监视对象Observer
        function Observer(obj){
            // 1、获取data当中的所有key值
            let properties = Object.keys(data); // ["name","age"]
    
            // 2、迭代 properties数组
            properties.forEach((property)=>{
                // 3、在迭代的过程当中,使用definedProperty进行数据代理
                Object.defineProperty(this,property,{
                    // 配置get和set
                    get(){
                        // 很简单,因为data没有做数据代理,返回data[property]即可
                        return data[property]; // data["name"] = waves
                    },
                    set(val){
                        // 赋值即可
                        data[property] = val
                    }
                })
            })
        }
    

    总结

    1. 我们这里设置了一个data
      • image-20221102115237706
    2. 通过我们的一系列配置,data身上有的属性,Observer实例身上也有
    3. 并且,这个observer身上的属性都做了数据代理
    4. 当然,vue写的比我们完善的多
    5. 比如,如果data当中还存在对象怎么办?

    image-20221102115801541

    vue在这里写了递归,一直找,找到这个属性不再是对象为止

    image-20221102120105239

    数组也是一个道理,vue也能给你找出来,不过 关于数组和对象的代理,这二者的处理方式不同,下节会讲解

  • 相关阅读:
    机器学习笔记--数学库
    使用Umi 遇到的错误
    量化金融模型ARCH模型官方例程(中文翻译版)
    Git常用命令(面试+复习)
    MapReduce Crashed SQL
    STM32 IWDG&WWDG
    hive数据初始化
    护理管理学名词解释
    Qt 大型工程项目的搭建过程,模块分类详解
    专业级科目一练习
  • 原文地址:https://www.cnblogs.com/wavesbright/p/16851727.html