1、vue2.0 响应式数据的原理
概述:Object.defineProperty()
递归数据劫持+订阅发布者模式
Vue2.0在初始化数据时,会给data中的属性使用Object.defineProperty
重新定义所有属性,当页面取到对应属性时,会进行依赖收集(收集当前组件的watcher)如果属性发生变化会通知相关依赖进行更新操作。
源码:src/observer/index.js
/**
* 类 Observer ,抽象了对象的公共部分,之后用这个类来实例化对象。
* constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法
* 类中添加方法有:def(改变对象的可遍历性)、walk(观察对象) 、observeArray(观察数组)
*/
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
// 增加dep属性(处理数组时可以直接调用)
this.dep = new Dep()
this.vmCount = 0
// 将Observer实例绑定到data的__ob__属性上面去,后期如果oberver时直接使用,不需要从新Observer,
// 处理数组是也可直接获取Observer对象
// Define a property.
def(value, '__ob__', this) //value是data,'__ob__'为属性名, this是observer实例
export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,//是否可遍历
writable: true,
configurable: true
})
}
if (Array.isArray(value)) {
// 判断数组
if (hasProto) {
//如果已经更改过原型
//通过截获原型链来扩充目标对象
protoAugment(value, arrayMethods)
} else {
//没有更改过原型,则通过定义隐藏属性来扩充目标对象或数组。
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)//观察数组
} else {
// 测试对象
this.walk(value);//遍历对象,调用defineReactive()使每个属性变为响应式数据
}
}
/**
* 遍历对象,调用defineReactive()