Vue的数据响应式原理

数据响应式原理在面试的时候会经常遇到,今天搞懂了,分享一下。
 
//使用了观察者模式
//总体思路:
//   1、observe(){} 监听数据的函数
//   2、对象拦截函数
//   3、数组劫持函数

 

let data = {
    username:'Ycenkun',
    age:'18',
    company:{
        name:'杭州'
    },
    arr:[1,2,3,4,5,6]
}

 

//数组劫持函数
const proto = Object.create(Array.prototype)//创建一个新对象,使用现有对象为新创建的对象提供__proto__
//新对象proto具有数组原型上所有的方法
const arrMethods = ['push','pop','shift','unshift','join','indexof','slice','splice','reverse','sort']
arrMethods.map((item)=>{
    proto[item] = function(){ //假如执行了push方法,那么就相当于执行了这个函数,而且这个proto已经成为data实例的原型方法
        Array.prototype.push.call(data.arr,...arguments) //既然重写这个方法,那么就要真正再实现这个方法,即再利用原型上的方法,不过需要改变this指向
        render(item,...arguments)
    }
})



//需要监听数据的函数 【数据改变会走set(){},但是由于set不能识别对象 所以set函数中也会用到这里】
function observe(data){
    // console.log(data)
//判断对象的类型
    if(Array.isArray(data)){ //如果是数组,要用数组劫持来处理
        // console.log(data)
        data.__proto__ = proto  //data是一个实例化的数组(我们不让他走自己的原型对象上的方法,
                                //而是我做一个必要的多此一举,自己控制原型对象的方法,所以触发原型对象的方法的时候,
                                //我们可以做一些自己想做的事情) data.__proto__就指向数组原型对象,而proto恰好是数组原型对象内的
                                //所有方法,那么即把数组的方法又全部继承给了data这个数组
    }                           //data的方法是继承于proto 然而proto的方法被重写了
    if(Object.prototype.toString.call(data) == '[object Null]'){ //空的不做任何处理
        return 
    }
    if(Object.prototype.toString.call(data) == '[object Object]'){  //如果是对象 交给对象拦截处理
        // console.log(data)
        for(let key in data){
            reactive(data,key,data[key])   //调用对象拦截函数处理
        }
    } 
}

 

//对象拦截函数
function reactive(obj,attr,value){
    observe(value) //当初始值是对象的时候,需要重新再走一次监听函数  递归直到剥离出value不是对象而是个值
    Object.defineProperty(obj,attr,{
        get(){ //获得初始值
            return value;
        },
        set(val){  //获得最新值,数据只要改变就要走到这里重新操作,所以数据一旦改变就会触发
            // console.log(`${attr}发生了改变,变成${val}`); //监听到数据改变
            // observe(val)   //当改变的值是个对象的时候,需要再走一次监听函数,剥离出来最终改变的值
            render(attr,val)
        }
    })
}

 

function render(who,res){
    console.log(`${who}发生了改变,改变的值是${res}`)
}

 

observe(data)


//node.js环境下测试:

// data.username = 'Cooper';
// data.age = 25;
// data.company={
//     name:'山东'
// }
//data.company.name='山东'
// data.arr.push(456)

 

posted @ 2020-09-05 16:06  Limerence`  阅读(180)  评论(0编辑  收藏  举报