Vue响应式原理
我们知道Vue的响应式,即当我们在控制台通过类似于app.message='hello'的操作, 修改挂载到app上data中message属性的值,就可以修改当前视图所显示的值。那Vue为什么可以做到这种响应式呢?我们第一时间就会想到对该属性进行监听,那么Vue内部具体是怎么完成的呢?

如何监听?
当new Vue()之后,初始化时Observer(观察者)调用Object.defineproperty方法对data中每个属性进行数据劫持和监听,并为data中的每个属性创建一个Dep对象(依赖对象)。Dep对象中有一个由所有该对象的订阅者组成的数组。这样我们就可以知道该属性都是谁在使用。
什么是订阅者(Watcher)?
在解析el模板指令时,每个模板指令都回调需要展示的属性的get方法,为每条指令创建一个Watcher实例。然后该属性的Dep对象调用添加订阅者方法(例如:addSubs)将订阅者实例添加到Dep的订阅者数组中。【Watcher的个数与模板中表达式一一对应】
知道了属性如何被监听,被谁监听。那么修改属性的值如何使视图中的值也随之改变?
Object.defineProperty方法中为每个data属性定义了一个set方法一个get方法,set用于对值的更新,get用于watcher创建完回调函数渲染视图。所以当监听到属性的值发生改变时,就调用set方法将新的Value赋值给旧的值,并且调用dep.notify()的方法,遍历该Dep对象中的订阅者数组,使得每个订阅者调用update()方法,updata就是对视图进行更新。
还是看代码
<script>
const obj = {
message1: "1",
message2: "2"
}
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
set(newValue){
value = newValue
dep.notify()
},
get(){
const dep = new Dep()
return value
}
})
})
class Dep {
constructor(){
this.subs = [] //记录谁订阅了属性
}
addSub(watcher){
this.subs.push(watcher)
}
notify(){
this.subs.forEach(item => {
item.update()
/*
为什么item可以调用update方法,因为每个item元素
都是一个Watcher对象实例
*/
})
}
}
class Watcher{
constructor(name){
this.name = name
}
update(){
}
}
const dep = new Dep() //拦截之后为每个属性创建一个Dep
const watcher1 = new Watcher() //解析模板指令后,每个指令都是一个Watcher对象
dep.addSub(watcher1) /*将对象加入订阅者数组,
就可以知道哪些对象监听了哪个属性,当属性发生改变新的value被赋值,
就调用notify()遍历这个属性的所有订阅者,每个订阅者都进行update。
最后视图也被更新,实现响应式 */
</script> 


京公网安备 11010502036488号