1、前言理解:
vue 一大特性数据驱动即数据更改驱动视图的变化 所以 数据变化监测是很重要的步骤 实现原理 js的Object.defineProperty 方法
2、观测Object数据 :
Object.defineProperty(obj, params, {
enumerable: true,
configurable: true,
get(){
console.log('price属性被读取了')
return val
},
set(newVal){
console.log('price属性被修改了')
val = newVal
}
})
通过defineProperty 中的set 和 get 可以观测到某个属性的读和写的操作
3、通过递归观测所有的属性
/**
* Observer类会通过递归的方式把一个对象的所有属性都转化成可观测对象
*/
export class Observer {
constructor (value) {
this.value = value
// 给value新增一个__ob__属性,值为该value的Observer实例
// 相当于为value打上标记,表示它已经被转化成响应式了,避免重复操作
def(value,'__ob__',this)
if (Array.isArray(value)) {
// 当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])
}
}
}
/**
* 使一个对象转化成可观测对象
* @param { Object } obj 对象
* @param { String } key 对象的key
* @param { Any } val 对象的某个key的值
*/
function defineReactive (obj,key,val) {
// 如果只传了obj和key,那么val = obj[key]
if (arguments.length === 2) {
val = obj[key]
}
if(typeof val === 'object'){
new Observer(val)
}
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get(){
console.log(`${key}属性被读取了`);
return val;
},
set(newVal){
if(val === newVal){
return
}
console.log(`${key}属性被修改了`);
val = newVal;
}
})
}
给value
新增一个__ob__
属性,值为该value
的Observer
实例。这个操作相当于为value
打上标记,表示它已经被转化成响应式了,避免重复操作
然后判断数据的类型,只有object
类型的数据才会调用walk
将每一个属性转换成getter/setter
的形式来侦测变化。 最后,在defineReactive
中当传入的属性值还是一个object
时使用new observer(val)
来递归子属性,这样我们就可以把obj
中的所有属性(包括子属性)都转换成getter/seter
的形式来侦测变化。 也就是说,只要我们将一个object
传到observer
中,那么这个object
就会变成可观测的、响应式的object
。