vue版本:v2.7.10
首先看一下数据初始化函数initData。
src/core/instance/state.ts
function initData(vm: Component) {
let data: any = vm.$options.data
data = vm._data = isFunction(data) ? getData(data, vm) : data || {}
...
const ob = observe(data)
...
}
export function observe(
value: any,
shallow?: boolean,
ssrMockReactivity?: boolean
): Observer | void {
...
ob = new Observer(value, shallow, ssrMockReactivity)
return ob
}
initData最核心的的实现是observe(data),而observe(data)则是创建了一个Observer实例, 接下来我们看一下Observer类。
Observer
src/core/observer/index.ts
export class Observer {
dep: Dep
vmCount: number // number of vms that have this object as root $data
constructor(public value: any, public shallow = false, public mock = false) {
this.dep = mock ? mockDep : new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (isArray(value)) {
// 数组的响应式处理
for (let i = 0, l = arrayKeys.length; i < l; i++) {
const key = arrayKeys[i]
def(value, key, arrayMethods[key])
}
if (!shallow) {
this.observeArray(value)
}
} else {
// 非数组对象的响应式处理
const keys = Object.keys(value)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock)
}
}
}
observeArray(value: any[]) {
for (let i = 0, l = value.length; i < l; i++) {
observe(value[i], false, this.mock)
}
}
}
对于响应式数据,其内部会创建一个Dep实例,接下去,数组类型和非数组对象类型是不同处理方式
- 数组的响应式处理看另外一篇文章->
- 非数组对象的响应式处理
非数组对象的响应式处理
遍历对象,使用defineReactive对对象的每个属性单独处理。
export function defineReactive(
obj: object,
key: string,
value?: any,
customSetter?: Function | null,
shallow?: boolean,
mock?: boolean
) {
const dep = new Dep()
let childOb = !shallow && observe(val, false)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter(newVal) {
const value = getter ? getter.call(obj) : val
if (!hasChanged(value, newVal)) {
return
}
val = newVal
childOb = !shallow && observe(newVal, false, mock)
dep.notify()
}
})
return dep
}
defineReactive代码这里做了简化,只保存最核心的部分,可以看到每个属性都创建了一个闭包变量dep.通过Object.defineProperty的get和set函数拦截了属性的取值和赋值操作。
- 在get函数中。通过dep.depend()将dep添加当前的Wather实例(保存在Dep.target)的依赖列表newDeps中,同时将当前Wather实例添加dep的订阅列表subs中。这里返回的value是作为一个可变的闭包变量,在set函数中可以修改这个值。
src/core/observer/dep.ts
depend() {
if (Dep.target) {
Dep.target.addDep(this)
}
}
src/core/observer/watcher.ts
addDep(dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}
- 在get函数中,value被最新的值覆盖,通过observe将最新的值处理成响应式数据。然后通过dep.notify遍历dep的订阅列表(Watcher列表),通知进行更新
src/core/observer/watcher.ts
notify(info?: DebuggerEventExtraInfo) {
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
src/core/observer/watcher.ts
update() {
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
this.run()
} else {
queueWatcher(this)
}
}
run() {
if (this.active) {
const value = this.get()
if (
value !== this.value ||
isObject(value) ||
this.deep
) {
const oldValue = this.value
this.value = value
if (this.user) {
const info = `callback for watcher "${this.expression}"`
invokeWithErrorHandling(
this.cb,
this.vm,
[value, oldValue],
this.vm,
info
)
} else {
this.cb.call(this.vm, value, oldValue)
}
}
}
}
update 函数最终是调用this.cb实现更新。对于三种类型的Watcher,各自对应的是:
- watch Watcher:watch的回调函数
- computed Watcher: 调用生成新的computed值的回调函数
- 渲染Watcher: 调用渲染函数,生成新的组件Dom元素