Vue源码解析之数据响应系统的使用(7)

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)
}

      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/19.html