为什么要用proxy代替defineProperty

文章目录

  • vue3-为什么要用proxy代替defineProperty
  • 1. 什么是Object。defineProperty,怎么实现的vue2响应式
  • 2. proxy,专为代理对象而生
  • 3. 总结

vue3-为什么要用proxy代替defineProperty

1. 什么是Object。defineProperty,怎么实现的vue2响应式

  • 在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
  • 怎么实现呢
  • 通过defineProperty的两个属性,get和set
  1. get
  • get本质是属性的getter函数,说白了就是如果访问一个属性,会调用改属性的getter函数。getter返回的值就是属性的值
  1. set
  • set本质是属性的setter函数,说白了就是如果给属性赋值,会调用该属性的setter函数,该方法接受一个参数,就是被赋予的新值
  • 那具提怎么实现呢
function effect(){// 副作用函数
    console.log('我是副作用函数,我可以被触发')
}
function reactive(obj,key,val){
    Object.defineProperty(obj,key,{
        get(){
            console.log(`get ${key}:${val}`)
            return val
        },
        set(newVal){
            if(newVal!==val){
                val=newVal
                effect()
            }
        }
    })
}
let obj={
}
reactive(obj,'name','')
obj.name='tom'
  • 调用reactive,数据发生变化时,会触发effect方法,实现数据响应式
  • 如果有多个key就需要进行遍历
function observer(obj){
    Object.keys(obj).forEach(key=>{
        reactive(obj, key, obj[key])
    })
}
  • 如果有嵌套对象,还需要进行递归
function defineReactive(obj, key, val) {
     observe(val)
     Object.defineProperty(obj, key, {
         get() {
             console.log(`get ${key}:${val}`);
             return val
        },
     set(newVal) {
         if (newVal !== val) {
             val = newVal
             update()
        }
     }
     })
}
  • 通过这样的方式实现了基本的响应式,但是如果我们不是读取或者赋值,而是直接删除或者新增,或者对数组的API进行操作,这种响应式就无法劫持到了,于是增加了set,deleteAPI
  • 但是如果存在较深的嵌套对象关系,会造成极大地性能问题

2. proxy,专为代理对象而生

  • Proxy的监听是针对对象的,所以对象的所有操作都可以监听到,可以代理所有的属性
function  reactive(obj){
    if(typeof obj!=='object' && obj!==null){
        return obj
    }
    const proxy=new Proxy(obj,{
        get(target,key,receiver){
            console.log('getter')
            return Reflect.get(target,key,receiver)
        },
        set(target,key,value,reciever){
            console.log('setter')
            return Reflect.set(arget,key,value,reciever)
            return isObject(Reflect.set(arget,key,value,reciever))?reactive(res):Reflect.set(arget,key,value,reciever)//针对对象嵌套,如果属性是对象,就继续reactive
        },
        deleteProperty(target,key){
            console.log('delete')
            return Reflect.deleteProperty(arget,key,value,reciever)
        }
    })
    return proxy;
}
const obj=reactive({
    name:'tom'
})
//obj此时已经是响应式得了

3. 总结

  • defineProperty只能通过属性遍历,劫持属性
  • proxy能对整个对象进行代理劫持

你可能感兴趣的:(vue3,javascript,前端,vue.js,proxy,defineProperty)