Vue中的数据代理

1,922 阅读5分钟

前言: 不知道大家在学习vue的时候,有没有这些疑问。什么是数据的双向绑定?vue是如何检测到我的数据改变了呢?vue中到底是怎么实现数据改变,模板就会重新解析的呢?为什么数组的更新数据方式和对象不同呢?多交流,少疑惑。在这里,我想和大家分享一点我学习到的和一些理解。如果有不足之处还希望能够指点。

1632434551568.jpeg

数据代理

一、什么是数据代理

Vue中,其实有很多运用到了数据代理的地方,所谓代理,可以理解成一个中间商(Vue),你把产品(数据) 交由她托管,当客户想要查询商品价格(想要访问数据) 时,中间上就会找到你去询问价格,然后把结果展示给客户。其实这就是一个简单的代理。那么这个逻辑在Vue中是如何实现的呢?

二、数据代理简单原理

大致理解代理后,想要理解Vue中的数据代理,就要先提到一个很重要的API “Object.defineProperty()”。不知道小伙伴们还是否熟悉它的用法(不熟悉的速速百度)。他有三个参数,Object.defineProperty(property,'attribute',{options}),第一个是指哪一个对象,第二个是指要代理的属性,第三个就是配置项。Vue实现数据代理的方法其实就是大量运用了该方法。配置项的其他内容在这里就不说了,主要说一下get()和set()方法。假设此时有一个需求: ``

动态的将num的值赋值给小红的age属性

        //此时,有的同学可能就会想到可以这样写
        let num = 18
        let person = {
            name: '小红',
            age: num
        }
        
        //{name:"小红","20"}

“ 这么做雀氏将num的值赋给了age,但是他不是动态的,此时如果更改num的值,age是没有反应的 ”

image.png

“ 所以此时我们要用到Object.defineProperty:

    let num = 12
        let person = {
            name: '小红',
        }
Object.defineProperty(data,"age",{
            // value:20,
            // enumerable:true,    //是否枚举
            // configurable:true,  //是否可删除
            // writable:true       //可修改的

            get(){
                console.log("有人读取了当前的num值")   //get()的作用就是,当有人读取了age属性时,get()就会被调用
                return num
            }
        })

“ 这时候就会发现这个age变得有点不一样 "

image.png

“为什么这个age后面变成(...)了?” 其实这个就相当于是代理了,我们不去询问(点击)的时候,person不会告诉我们age是多少,当我们想访问(点击...)的时候,就会触发ageget(其实就是叫getter)方法,然后get方法返回num的值作为agevalue。这样,当num改变时,我们就能动态获取num的值啦!

image.png

image.png

那么接下来同理,有getter,就会有setter,顾名思义,setter就是当有人想改变perosonage的值时就会被调用。此时重新有个新需求,我想吧age的年龄值改成100,肯定会有小伙伴想到这样写:

person.age = 100    //我们来看一下结果

image.png

image.png

这时发现age的值依旧是12,刚刚明明修改过了age的值了啊?? 其实原因很简单,我们的age它的值是只和num有关的,因为我们访问age时,他总返回的是num的值,num不变,age就不会变的。“这简单,那我把num的值一改不就得了”。肯定会有小伙伴有这样的想法吧😏~。在这里,既然我们呢选择了代理,那我们就不需要去直接修改源数据。(也可以理解成我们自己改商品价格就行,不用问你了),那么看接下来的操作:

      let num = 12  //对象1
        let person ={  //对象2   也即是对象2代理了对象1中的num
            name:"小红",
            age:num
        }
        
        Object.defineProperty(person,"age",{
            // value:20,
            // enumerable:true,    //是否枚举
            // configurable:true,  //是否可删除
            // writable:true       //可修改的

            get(){
                console.log("有人读取了当前的num值")   //当有人读取了age属性时,get()就会被调用
                return num
            },
            set:function (value){  //set(){}是简写形式
                console.log("有人修改了当前age的值")      
                //当有人修改了age时,set就会被调用,并且set(value)还可以收到修改的值是多少
                num = value   //将新的值赋值给num,这样就实现了一个类似于双向的绑定!
            }
        })

" 这时候,我们再去修改age的值!!"

image.png "发现age的值变了!!"

到这里,大家有没有嗅到一点vue中监测数据变化的味道呢😏?接下来我们就看一看vue中的数据监测和代理是怎样的~

三、Vue中的数据代理

先看如下代码:

...
    <div id="root">
       <h1>姓名:{{name}}</h1>    
        <h1>年龄:{{age}}</h1>
    </div>
...
const vm = new Vue({
            el:"#root",         //vue中的数据代理 
            data:{            
                name:'小花',
                age:20
            }
        })
        //看效果

image.png

这时候,我们看先一下Vue的实例对象,vm身上有什么东西

image.png

vm身上有很多属性和方法,但其中有两个属性我们很眼熟,这不就是我们刚刚写的东西吗?再点看一下

image.png

到这里,其是这个就是**vue中的数据代理**了,同样他也有getter和setter

image.png

此时,如果我们更改age的值,vue就对界面重新解析

image.png

我们还可以通过另一种方式去修改age的值。大家仔细观察的话,vue的身上有一个_data对象,里边的内容和我们写在data中的数据内容是一样的。

image.png 如果我们这样修改:

    vm._data.age = 30

image.png 我们发现,age也被修改了。到这里,我们其实就发现了他监测数据改变的原理了。这里我给大家做一个总结。

总结 其实vue在这里做了一件很聪明的事。 在这里,vm 拿到data中的数据后,放在了vm里的_data中。实际上data就是_datavm中的age代理了_data中的age。读取vm.age时,调用get方法,读取了_data中的age。修改了vm中的age时,就会调用set方法去修改_data中的age。估计会有人想为什么要多此一举呢?其实,如果不做代理,那么在“{{  }}”中就要这样写了“{{_data.xxx}}”,会很麻烦。如果想要验证_data是否等于data。可以这样验证。

    vm._data === options.data(options指的是当时new Vue时候的配置对象,也就是()里的)
    
    //true

图例分析

image.png

好啦,分享就暂时到这里啦,主要还是偏新手向,有不足的地方欢迎指点~

69709778a396c801.gif 1ac902f2c3708f7f.gif