vue的响应式原理
当你把一个普通的 JavaScript 对象传给 Vue 实例的
data
选项时,Vue 将遍历此对象所有的属性,并使用Object.defineProperty
把这些属性全部转为getter/setter
,这些getter/setter
对用户来说是不可见的,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化,每个组件实例都有相应的watcher
实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter
被调用时,会通知watcher
重新计算,从而致使它关联的组件得以更新。Vue 响应系统,其核心有三点:
observe
、watcher
、dep
:
observe
:遍历data
中的属性,使用 Object.defineProperty 的get/set
方法对其进行数据劫持;dep
:每个属性拥有自己的消息订阅器dep
,用于存放所有订阅了该属性的观察者对象;watcher
:观察者(对象),通过dep
实现对响应属性的监听,监听到结果后,主动触发自己的回调进行响应。
computed的实现原理
- 当组件初始化的时候,
computed
和data
会分别建立各自的响应系统,Observer
遍历data
中每个属性设置get/set
数据拦截初始化
computed
会调用initComputed
函数
- 注册一个
watcher
实例,并在内实例化一个Dep
消息订阅器用作后续收集依赖(比如渲染函数的watcher
或者其他观察该计算属性变化的watcher
)- 调用计算属性时会触发其
Object.defineProperty
的get
访问器函数- 调用
watcher.depend()
方法向自身的消息订阅器dep
的subs
中添加其他属性的watcher
- 调用
watcher
的evaluate
方法(进而调用watcher
的get
方法)让自身成为其他watcher
的消息订阅器的订阅者,首先将watcher
赋给Dep.target
,然后执行getter
求值函数,当访问求值函数里面的属性(比如来自data
、props
或其他computed
)时,会同样触发它们的get
访问器函数从而将该计算属性的watcher
添加到求值函数中属性的watcher
的消息订阅器dep
中,当这些操作完成,最后关闭Dep.target
赋为null
并返回求值函数结果。- 当某个属性发生变化,触发
set
拦截函数,然后调用自身消息订阅器dep
的notify
方法,遍历当前dep
中保存着所有订阅者wathcer
的subs
数组,并逐个调用watcher
的update
方法,完成响应更新。