Observer也定义在core/observer/index.js文件中,它是一个构造函数,用来将数据对象转换成响应式的。
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]) } } /** * Observe a list of Array items. */ observeArray (items: Array<any>) { for (let i = 0, l = items.length; i < l; i++) { observe(items[i]) } } }
以上是Observer的全部代码,现在我们从constructor开始,来看一下实例化Observer都做了什么。
__ob__ 属性
constructor开始先初始化了几个实例属性
this.value = value this.dep = new Dep() this.vmCount = 0 def(value, '__ob__', this)
value就是实例化Observer时传递的参数,现在将它赋给了实例对象的value属性。dep属性指向实例化的Dep实例对象,它就是用来收集依赖的容器。vmCount属性被初始化为0.
接着使用def函数为数据对象添加了__ob__属性,它的值就是当前Observer实例对象。def定义在core/util/lang.js文件中,是对Object.defineProperty的封装。
export function def (obj: Object, key: string, val: any, enumerable?: boolean) { Object.defineProperty(obj, key, { value: val, enumerable: !!enumerable, writable: true, configurable: true }) }
用def来定义__ob__属性是要把它定义成不可枚举的,这样遍历对象就不会遍历到它了。
假设我们的数据对象是
data = { a: 1 }
添加__ob__属性后变成
data = { a: 1, __ob__: { value: data, // data 数据对象本身 dep: new Dep(), // Dep实例 vmCount: 0 } }
处理纯对象
接下来是一个if...else判断, 来区分数组和对象,因为对数组和对象的处理不同。
if (Array.isArray(value)) { if (hasProto) { protoAugment(value, arrayMethods) } else { copyAugment(value, arrayMethods, arrayKeys) } this.observeArray(value) } else { this.walk(value) }
内容版权声明:除非注明,否则皆为本站原创文章。