【core/observer】之Observer类
程序员文章站
2024-01-08 17:01:40
/** * Observer 类会附加到每一个被侦测的Object上 * 一旦被附加上,Observer会将Object的所有属性都转换 * 为getter/setter的形式来手机属性的以来 * 并且当属性变化时会通知这些依赖 */export class Observer { value: any; dep: Dep; vmCount: number; // 具有该对象作为根$data的vm的数量 constructor (value: any) { this.va...
/**
* Observer 类会附加到每一个被侦测的Object上
* 一旦被附加上,Observer会将Object的所有属性都转换
* 为getter/setter的形式来手机属性的以来
* 并且当属性变化时会通知这些依赖
*/
export class Observer {
value: any;
dep: Dep;
vmCount: number; // 具有该对象作为根$data的vm的数量
constructor (value: any) {
this.value = value
this.dep = new Dep() // 用来存放array的依赖
this.vmCount = 0
/**
* 给每一个值的原型上新增一个‘__ob__‘属性
* ‘__ob__‘属性的值就是当前Observer的实例
* 通过这个属性就可以拿到数组的依赖了
*/
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方法会将每一个属性都转换成getter/setter
* 的形式来侦测变化,这个方法只在数据类型时
* Object的时候被调用
*/
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类,这个类,就是给每一个对象,添加一个 __ob__
属性,并且把这个对象,变成getter/setter形式。变成这样的形式呢,会方便收集依赖,并且在数据发生变化的时候,通知各个依赖。
相关方法
-
Dep
类里面使用this.dep = new Dep()
,是为了存放数组的依赖,因为数组在getter的时候收集依赖,在拦截器里触发依赖,将数组的依赖放在Observer的实例上,是为了让数组的getter和拦截器中都能访问到。 -
def()
这个方法,是用来处理value,给它添加一个__ob__
的属性,这个属性的值就是当前Observer的实例,因为数组的依赖保存在Observer的实例上,所以添加这个值,就可以在拦截器中访问Observer实例,并拿到相应的依赖。
/**
* 定义一个属性.
*/
function def (obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
// Observer 类中
def(value, '__ob__', this)
- 判断value是对象还是数组,如果是对象的话,就走walk方法,walk方法就是把object自身有的属性遍历一边,然后用
defineReactive()
方法全部转换成getter/setter形式 - 如果是数组对象,就需要先判断一下,浏览器能不能支持
__proto__
这个属性,为什么要判断这个属性?因为数组的某些原型中的方法,需要覆盖,通过判断hasProto
来用两种方法来处理覆盖value原型的功能,支持__proto__
,使用protoAugment()
函数覆盖原型,如果不支持,则调用copyAugment()
函数将拦截器中的方法挂载到vulue上。
/**
* 使用__proto__截取原型链来增强目标对象或数组
*/
function protoAugment (target, src: Object) {
/* eslint-disable no-proto */
target.__proto__ = src
/* eslint-enable no-proto */
}
/**
* 通过定义一个隐藏属性来增强目标对象或数组
*/
/* istanbul ignore next */
function copyAugment (target: Object, src: Object, keys: Array<string>) {
for (let i = 0, l = keys.length; i < l; i++) {
const key = keys[i]
def(target, key, src[key])
}
}
-
observeArray()
方法
循环Array中的每一项,执行observe函数来侦测变化,通过observe函数,将数组中的每一个元素都执行一遍new Observer()
。 observe()
/**
* 尝试为value创建一个Observer的实例。
* 如果创建成功,直接返回新创建的Observer实例
* 如果value已经存在一个Observer实例,就直接返回它
*/
export function observe (value: any, asRootData: ?boolean): Observer | void {
// 不是对象或者不是VNode的实例,就返回
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
// 有observer实例就返回该实例
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
}
本文地址:https://blog.csdn.net/u014627807/article/details/107155470
上一篇: Android优化笔记--崩溃优化
下一篇: XTS测试及常见问题