vue响应原理详解(一看就懂)
vue相应原理依靠的是Object的defineProperty方法,
该方法提供了给对象定义一个新属性,和修改现有属性的操作
defineProperty方法,参数为对象 、操作的属性 、 和属性描述
其中属性描述可以控制对象的修改,删除,迭代
1、value定义了操作的属性值
2、默认情况下defineProperty新增的属性writable为false代表着不可修改该属性,为true时则可以修改该属性
3、默认情况下defineProperty新增的属性configurable为false代表着不可删除该属性,为true时则可以删除该属性
4、默认情况下defineProperty新增的属性enumrable为false代表着不可迭代该属性,为true时则可以迭代该属性
defineProperty方法在执行的修改新增的同时可以添加get与set方法
get与set方法实现了vue的双向绑定,当我们去查看defineProperty方法定义的属性时,会自动的调用get方法此时可以return我们想要输出的变量,set方法则是在修改时触发,但我们无法确定修改后的属性是否和原属性一致,为了不出现多余的修改,可以添加if判断如果新值与旧值相同则不去修改赋值。
不过如果确认使用get和set方法,因为是借由get/set操作的查看与修改的过程,那么原来的defineProperty的value和writable方法都不可使用了,会出现冲突报错。
由此产生了一个问题,如果说我们监听一个属性那么很容易,但如果是多个属性那么我们怎么办那,总不能每次的新属性都去在写一次defineProperty方法吧。
这时es6类的概念就派上了用场,解决多个属性监听所使用的方法就是calss
将需要监听的对象传给class类,这个既可以给传入的所有属性都添加get/set方法
那么怎么使用calss类解决的这个问题那,各位看官下面将分为步骤详解
/*
需求: 快速监听对象中所有属性的变化
* */
let obj = {
name: 'str',
// name: {a: 'abc'},
age: 10
};
// 只要将需要监听的那个对象传递给Observer这个类
// 这个类就可以快速的给传入的对象的所有属性都添加get/set方法
class Observer{
// constructor可以接收到new Observer(obj)的传值对象
constructor(data){
// 此处调用的observer方法,即将calss传入的对象抛给 observer方法接收
this.observer(data);
}
observer(obj){
if(obj && typeof obj === 'object'){
// 遍历取出传入对象的所有属性, 给遍历到的属性都增加get/set方法
for(let key in obj){
this.defineRecative(obj, key, obj[key])
}
}
}
// obj: 需要操作的对象
// attr: 需要新增get/set方法的属性
// value: 需要新增get/set方法属性的取值
defineRecative(obj, attr, value){
// 如果属性的取值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
this.observer(value);
Object.defineProperty(obj, attr, {
get(){
return value;
},
// 注意set改用箭头函数的原因是因为this指向
set:(newValue)=>{
if(value !== newValue){
// 如果给属性赋值的新值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
this.observer(newValue);
value = newValue;
console.log('监听到数据的变化,代表可以更新view层');
}
}
})
}
}
new Observer(obj);
// obj.name = '测试';
// obj.age = 123;
// obj.name.a = '对象a的修改';
obj.name = {a: '测试'};
obj.name.a = '对象a的修改';
这其实也变相解释了为何vue的数据会丢失,因为defineProperty方法可以监听对象的数据变化,而数组的却不能很好的去处理,感兴趣的可以去百度一下