/**
* Attempt to create an observer instance for a value,
* returns the new observer if successfully observed,
* or the existing observer if the value already has one.
*/
export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value)
}
if (asRootData && ob) {
ob.vmCount++
}
return ob
}
这里会通过new Observer(value)创建一个Observer实例,实现对数据的观测。
第三步是实现对对象的处理。对应源码src/core/observer/index.js的55行。
/**
* Observer class that is attached to each observed
* object. Once attached, the observer converts the target
* object's property keys into getter/setters that
* collect dependencies and dispatch updates.
*/
export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
/**
* Walk through all properties and convert them into
* getter/setters. This method should only be called when
* value type is Object.
*/
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
// ...
}
Vue
实现响应式数据的核心API
是Object.defineProperty
。其实默认
Vue
在初始化数据时,会给data
中的属性使用Object.defineProperty
重新定义所有属性,当页面取到对应属性时。会进行依赖收集(收集当前组件的watcher
) 如果属性发生变化会通知相关依赖进行更新操作。这里,我用一张图来说明
Vue
实现响应式数据的流程:首先,第一步是初始化用户传入的
data
数据。这一步对应源码src/core/instance/state.js
的112行第二步是将数据进行观测,也就是在第一步的
initData
的最后调用的observe
函数。对应在源码的src/core/observer/index.js
的110行这里会通过
new Observer(value)
创建一个Observer
实例,实现对数据的观测。第三步是实现对对象的处理。对应源码
src/core/observer/index.js
的55行。第四步就是循环对象属性定义响应式变化了。对应源码
src/core/observer/index.js
的135行。第五步其实就是使用
defineReactive
方法中的Object.defineProperty
重新定义数据。在get
中通过dep.depend()
收集依赖。当数据改变时,拦截属性的更新操作,通过set
中的dep.notify()
通知相关依赖进行更新。