proxy与defineProperty的差别

34 阅读2分钟
vue2响应式的原理是通过Object的一个方法,definProperty把一个对象的某个属性变成一个get和set函数,他是针对对象的某个属性的,他需要对对象进行深度遍历,对每个属性进行监听,当访这个属性或者修改时就会触发get和set函数.
const obj ={
a:1,
b:2,
c:{
a:1,
b:2,
};
function _isObject(v){
    return typeOf v === 'object' && v != null
}

function observe(obj){
    //我们要对传进来的每个对象进行遍历
    for(const k in obj){
        let v = obj[k];
        //如果遍历的时候该属性是一个对象,则在遍历一次
        if(_isObject(v)){
            observe(v)
        }
        Object.defineProperty(obj,k,{
        get(){
        console.log('a','读取')
        return v
        },
        set(val){
        if(val!==v){
        console.log('a','更改')
        v=val
        }
      }
})
   }

}
//观察
observe(obj)

这就是vue2响应式的做法,而他有一个天生的缺陷,他是针对每个属性的监听,所有他必须进行深度遍历,这会有效率的损失,由于他在观察这个步骤里面已经对对象进行了深度遍历,在这个时间里对象里面有的属性都被监听到了,都被改成get和set函数了,但是这个步骤一旦做完了,你去对这个对象进行新增,删除操作他是不知道的,因为监听步骤已经结束了, 在created钩子函数之前已经对对象进行了监听

vue3则是通过proxy对对象进行监听,他和vue2不同之处就是他是对整个对象进行监听,vue2的做法是直接去遍历对象的每一个属性,改动原始对象,监听他的每一个属性,而vue3则是产生一个新的代理对象,不会去动原始对象,后续对这个对象的每一个操作都是去操作这个代理对象
    //代理,后续对这个属性读取或者修改则是直接通过这个代理去做的
    function observe(obj){
    const proxy = new Proxy(obj,{
    //obj是读取的那个对象 k就是那个值
    get(obj,k){
    let v = obj[k]
    if(_isObject(v)){
        v=observe(v)
     }
    console.log(k,'读取')
    return v
    },
    set(obj,k,val){
    if(obj[k]!==val){
    obj[k]=val;
    console.log(k,'更改')
    }
    }
})
    return proxy
}
//生成代理对象
const proxy = observe(obj)