什么是vue2.x中Object的变化侦测?

199 阅读3分钟

痛定思痛,总要静一静,用抹布抹一抹陈旧模糊的记忆。

虽然截止至2023年12月31日,vue2.x版本已停止维护,但是vue2中的很多东西还是值得去思考的。

最经典的面试题莫过于:简述下Vue2的响应式原理~🤦‍♂️

what ?

什么是变化侦测?

说白话,就是界面视图发生改变时,需要有个人告诉我视图变了。

例:元宵节夜晚,当你一路向北行进时,背后方向忽然放起了烟花秀。迎面而来的一位美女,告诉了你。你转身回望赞叹了一句:“好漂亮~

变化的事件:烟花秀

侦测者:美女

How?

如何追踪变化?

那么绕不开的一个方法必然就是 Object.defineproperty() ,建议通读其对象属性以便加深理解与感悟。

通过对其封装,得到如下函数,其作用是定义一个响应式数据。即在其中进行变化追踪,封装的目的在于仅仅传递入参即可。

function defineReactive(data,key,val){ // 封装函数
  Object.defineProperty(data,key,{
    enumerable:true,
    configurable:true,
    get:function(){ // 获取(读)数据的值
      return val;
    },
    set:function(newVal){ // 设置数据的值
      if(val === newVal){
        return;
      }
      val = newVal;
    }
  })
}

关注点

  • 每当从data的key中读取数据是,get函数被触发
  • 每当往data的key中设置数据时,set函数被触发

封装的目的:收集依赖

🤕 依赖是啥?---> 变化的信息(比如:之前提到的烟花秀)

一句话总结:先收集依赖,在getter中收集依赖,在setter中触发依赖

ps【通读 **Object.defineproperty()**后很好理解】:

getter---> get()函数对应的属性

setter---> set()函数对应的属性

存放依赖

⛏ 为啥存?---> 计算机处理数据,在输入后,需要存储才能进行后续操作。

这里定义了一个Dep类来收集、删除依赖或向依赖发送通知。

有时候,为了让自己开心,Dep可以是任何我喜欢的名字(比如:BBQ🤪)。

export default class Dep {
    constructor() {
        this.subs = []
    }
    
    addSub(sub) {
        this.subs.push(sub)
    }
    
    removeSub(sub) {
        remove(this.subs, sub)
    }
    depend() {
        if(window.target) {
            this.addSub(windwo.target)
        }
    }
    
    notify() {
        const subs = this.subs.slice()
        for(let i = 0, l = subs.length; i < l; i++) {
            subs[i].update()
        }
    }
}

function remove (arr, item) {
    if (arr.length) {
        const index = arr.indexOf(item)
        if(index > -1) {
            return arr.splice(index, 1)
        }
    }
}

既然有地方存依赖了,那么响应式函数就可以改造了

function defineReactive (data, key, val) {
    let dep = new Dep() // 修改
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function () {
            dep.depend() // 修改
            return val
        },
        set: function () {
            if(val === newVal) {
               return 
            }
            val = newVal
            dep.notify() // 修改
        }
    })
}

什么是watcher?

Watcher是一个中介的角色,数据变化时通知它,他负责通知其他地方。(比如:之前例子中的美女😁)

美女告诉了我背后有烟花秀,所以我才知道,并发出了赞美。

想要侦测所有

美女告诉我有烟花秀,仅仅是一件事。如果想知道更多的事应该怎么办?

答:住院

你一旦有什么事,护士会立马通知你~🤣

此时,则需要一个新的类 Observer,来实现将一个正常的Object转换成被侦测的Object。

解决方案是递归实现,此处不再展开。

关于Object的问题

如上所述,递归将一个正常的Object转换成被侦测的Object。然而,仅仅涵盖了Object本身已有的属性。

故无法追踪新增属性和删除属性

总结

🤕🤕🤕 欢迎讨论交流~

image.png

E6BF3B4A.jpg