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>