Vue2.0 Vue监测数据的原理_对象

这篇博客详细解析了Vue如何实现数据响应式,包括数据代理、Object.defineProperty的使用以及Observer构造函数的角色。通过创建Observer实例来监视data对象,利用getter和setter实现数据变化的追踪,确保页面视图与数据同步更新。此外,还讨论了Vue如何处理深层对象和数组的变更检测。
摘要由CSDN通过智能技术生成

想要说明白this.persons[0] = {id:001,name:'马老师',age:50,sex:'男'}问题,你就必须要知道Vue是如何监测数组里面元素的改变

先看Vue是如何让监测对象里的数据改变的,随后引出它是怎么监测数组的

Vue是怎么监测对象里数据的改变的

<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
Vue.config.productionTip = false

const vm = new Vue({
    el: '#root',
    data(){
        return{
            name:'bilibili',
            address:'上海'
        }
    }
})

vm身上有什么:

> vm.name
< "bilibili"
> vm.address
< "上海"

这块叫数据代理,也就是data这一块数据最终最终vm一定会有

data里面的数据放到vm上,执行的vm._data = data其实是第二步了
第一步是加工data

> vm._data
< v{__ob__: Observer}
    address: (...)
    name: (...)
    __ob__: Observer {value: {…}, dep: Dep, vmCount: 1}
    get address: ƒ reactiveGetter()
    set address: ƒ reactiveSetter(newVal)
    get name: ƒ reactiveGetter()
    set name: ƒ reactiveSetter(newVal)
    [[Prototype]]: Object

data_data_data的name不再给的直接了,通过get name去给;当我要去修改name的时候通过set name去给

其实所谓的加工就是: 把你data里面写的每一组k-v都形成的getter setter写法

你所传入的data它拿到了之后,它执行了第一件事:加工data --> 大概是vm._data

加工一下就能做响应式了,什么是响应式?

数据变了,页面也跟着变,这就是响应式
当有一天你去修改了_data.name的时候就会引起set name的调用,这个set里面写了一个调用,这个调用就可以重新解析模板

name一改 --> set一调 --> set一调重新解析模板 --> 模板一重新解析,生成新的虚拟DOM --> 新旧DOM对比 --> 更新页面

Vue监测nameaddress的改变就是靠getset

若你自己写一个与之类似

let data = {
    name: 'bilibili'
}
Object.defineProperty(data,'name',{
    get(){
        return data.name
    }
    set(val){
        data.name = val
    }
})

这样表面没问题,但是不能读取和修改原因是:

如果有人读取name,调get(),get()里面写了data.name,data.name一执行,调get(),get()在执行data.name又执行;递归停不下来了
同理set(val)也是:当有人修改了data中的name,set()就被调用,set()一被调用data.name = val执行,data上的name只要一改就立马调用set()

所以要实现不是这么写的, vue底层写了个构造函数

//Observer:观察者/观察家/观测者/观察者模式
//它能创建一个能监视的实例对象,它能收到一个对象作为参数
function Observer(obj){

}

它想把你data里的数据进行监测它得靠Observer它拿到你所传入的data,它马上做了一件new Observer(data)事,然后它会收到Observer的实例对象const obs = new Observer(data)

let data = {
    name: 'bilibili'
}

//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)

我们在Observer(obj)写一写核心的东西,借助哪个api?
const keys = Object.keys(obj)然后开始遍历
在遍历之前看一下keys:console.log(keys)

Array(2)
    0: "name"
    1: "address"
    length: 2

然后开始遍历,你拿到的每一个可以用k作为形参

keys.forEach((k)=>{
    //函数体
})

技巧来了,Object.defineProperty(this)它往this里面添,你就要知道this是谁(this是实例对象不是data)往Observer实例对象身上添加一个属性,属性是得读取k的值(Object.defineProperty(this,k,{}));get()中把传入的obj身上所对应的属性的值交出去(return obj[k]);set()会收到你所修改的值,然后把传入的这个对象身上的k所对应的属性改掉(obj[k] = val)。这样就够用了

let data = {
    name: 'bilibili',
    address: '上海'
}

//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)

function Observer(obj){
    //汇总对象中所有的属性形成一个数组
    const keys = Object.keys(obj)
    //遍历
    console.log(keys)
    keys.forEach((k)=>{
        //函数体
        Object.defineProperty(this,k,{//this是实例对象不是data;实例对象身上添加一个属性
            get(){
                return obj[k]//把传入的obj身上所对应的属性的值交出去
            },
            set(val){
                obj[k] = val
            }
        })
    })
}

最后obs长什么样:

console.log(obs)

如果此时此刻准备一个vm实例对象

//准备一个vm实例对象
let vm = {}
vm._data = obs

data没变,你可以做的更完善一点:

vm._data = data = obs

set()里观察,写一个模板字符串

set(val){
    console.log(`${k}被改了,我要去解析模板,生成虚拟DOM,进行比较....我要开始忙了`)
    obj[k] = val
}
> vm._data === data
< true
> vm._data.name = "陈天羽"       
    name被改了,我要去解析模板,生成虚拟DOM,进行比较....我要开始忙了
< '陈天羽'

这只是模拟,vue比我们这个做的更好,它可以

> vm._data.name = 123
< 123

> v.name = 456
< 456

我们这里没有考虑对象里面还有对象的情况

Vue.config.productionTip = false

const vm = new Vue({
    el: '#root',
    data(){
        return{
            name:'bilibili',
            address:'上海',
            students:{
                1:{
                	name: 'tom',
                	age: 20
                }
            }
        }
    },
})
> vm._data
< {__ob__: Observer}
    address: (...)
    name: (...)
    students: Object
    1: Object
    __ob__: Observer
    dep: Dep {id: 6, subs: Array(0)}
    value: {__ob__: Observer}
    vmCount: 0
    [[Prototype]]: Object
    get 1: ƒ reactiveGetter()
    set 1: ƒ reactiveSetter(newVal)
    [[Prototype]]: Object
    __ob__: Observer {value: {…}, dep: Dep, vmCount: 1}
    get address: ƒ reactiveGetter()
    set address: ƒ reactiveSetter(newVal)
    get name: ƒ reactiveGetter()
    set name: ƒ reactiveSetter(newVal)
    get students: ƒ reactiveGetter()
    set students: ƒ reactiveSetter(newVal)
    [[Prototype]]: Object

无限的找下去,直到没有对象
哪怕你把东西放到数组里面,Vue也能找到

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

结城明日奈是我老婆

支持一下一直热爱程序的菜鸟吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值