那么问题是不是出现在对 questions 进行 getter 的过程中,出现了 O(n³) 的复杂度呢?
于是,我打开了 Vue 的源码,由于之前深入研究过源码,所以轻车熟路地找到了 vue/src/core/instance/state.js 里面将 data 转换成 getter/setter 的部分。
function initData (vm: Component) {
......
// observe data
observe(data, true /* asRootData */)
}
定义一个组件的 data 的响应式,都是从 observe 函数开始,它的定义是位于 vue/src/core/observer/index.js 。
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
}
observe 函数接受对象或者数组,内部会实例化 Observer 类。
export class Observer {
value: any;
dep: Dep;
vmCount: number;
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 (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
Observer 的构造函数很简单,就是声明了 dep、value 属性,并且将 value 的 _ ob _ 属性指向当前实例。举个栗子:
// 刚开始的 options
export default {
data : {
msg: '消息',
arr: [1],
item: {
text: '文本'
}
}
}
// 实例化 vm 的时候,变成了以下
data: {
msg: '消息',
arr: [1, __ob__: {
value: ...,
dep: new Dep(),
vmCount: ...
}],
item: {
text: '文本',
__ob__: {
value: ...,
dep: new Dep(),
vmCount: ...
}
},
__ob__: {
value: ...,
dep: new Dep(),
vmCount: ...
}
}
也就是每个对象或者数组被 observe 之后,多了一个 _ ob _ 属性,它是 Observer 的实例。那么这么做的意义何在呢,稍后分析。
继续分析 Observer 构造函数的下面部分:
// 如果是数组,先篡改数组的一些方法(push,splice,shift等等),使其能够支持响应式
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
// 数组里面的元素还是数组或者对象,递归地调用 observe 函数,使其成为响应式数据
this.observeArray(value)
} else {
// 遍历对象,使其每个键值也能成为响应式数据
this.walk(value)
}
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
// 将对象的键值转换成 getter / setter,
// getter 收集依赖
// setter 通知 watcher 更新
defineReactive(obj, keys[i])
}
}
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
内容版权声明:除非注明,否则皆为本站原创文章。
