vue的响应式原理源码分析

65 阅读2分钟

前言

相信使用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

image.png

而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)

image.png

这样就跟我们自己手动添加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

image.png

obj.a = 'a改变的值'

image.png

这样就给了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为属性,属性值为函数的键值对

image.png

在调用的时候使用原生数组方法后通知视图更新,

vue2总结

实际上vue2响应式原理就是在递归遍历对象,订阅每一个属性,这也是为什么用数组下标没办法改变属性值原因