前言
相信使用vue的朋友们,都会遇到面试官问vue的响应式原理是什么,本文就来记录一下我学习响应式原理后的理解
Object.defineProperty(obj,key,dec)
我们先要了解object.defineProperty到底为响应式做了什么,为什么要使用?
function createObj(){
return {
a:1,
b:2
}
};
let objValue = createObj();
console.log(objValue.a,'a')
objValue.a = 3;
console.log(objValue.a,'a赋值')
可以看到上述代码,我们可以对objValue对象的属性直接读取和赋值,还可以像下述代码一样自己手动设置增加扩展性
let obj ={
a:1,
get aGet(){
return this.a;
},
set aSet(newVal){
this.a = newVal;
}
}
console.log(obj)
let aValue = obj.aGet;
obj.aSet = 3;
console.log(aValue,obj.a)//1,3

而ES5的Object.defineProperty(obj,key,dec)刚好可以为对象属性添加getter,setter
function defineRective(obj,key,value){
Object.defineProperty(obj,key,{
get(){
return value;
},
set(newVal){
value = newVal;
}
})
}
let obj ={
a:1
};
defineRective(obj,'a',2);//
console.log(obj)

这样就跟我们自己手动添加get,set一样的效果,这样是不是我获取跟赋值对象属性的时候,能在get跟set函数中去操作
vue2处理对象的第一步,遍历对象
function observe(value){
if(typeof value !== 'object'|| value === null){
return;
};
for(let key in value){
defineRective(value,key,value[key]);
}
}
function defineRective(obj,key,value){
//对象属性值也是对象,进行递归遍历
observe(value)
Object.defineProperty(obj,key,{
get(){
console.log('进行get获取')
return value;
},
set(newVal){
console.log('进行set操作')
if(value !==newVal){
value = newVal;
}
}
})
}
let obj = {a:'a属性的值'};
observer(obj);
obj.a

obj.a = 'a改变的值'

这样就给了vue数据变化,set去更新视图的操作空间
对象属性值是数组时,同样会遍历数组进行observe(obj)
function observe(value){
if(typeof value !== 'object'|| value === null){
return;
};
if(isArray(value)){
//重写7个数组方法:调用7个原生数组方法操作数组,通知视图更新
value.__proto__ = arrayMethods;
observeArray(value)
}else{
for(let key in value){
defineRective(value,key,value[key]);
}
}
}
function observeArray(value){
for(let i = 0, l = value.length, i < l, i++){
observe(value[i])
}
}
为了保证使用数组方法改变时能通知视图更新,为每个数组实例的原型对象上增加了以push,unshift,shift,pop,sort,reserve,splice为属性,属性值为函数的键值对

在调用的时候使用原生数组方法后通知视图更新,
vue2总结
实际上vue2响应式原理就是在递归遍历对象,订阅每一个属性,这也是为什么用数组下标没办法改变属性值原因