那么问题是不是出现在对 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]) } }
内容版权声明:除非注明,否则皆为本站原创文章。