JS(15)Object.defineProperty与Proxy的比较(Vue3为何要使用Proxy)

1、Object.defineProperty()

1.1、基本使用

  • Object.defineProperty(obj,prop,descriptor)
  • obj:要添加属性的对象
  • prop:属性
  • descriptor:配置对象
let person = {}
let personName = '万人'
//给person添加一个'name'属性
Object.defineProperty(person,'name',{
    //getter,当访问该属性时触发
    get(){
        console.log('访问了name属性')
        return personName
    },
    //setter,修改了该属性时触发
    set(value){
        console.log('修改了name属性');
        personName = value
    }
})
//console   访问了name属性 
//console   万人
console.log(person.name)  


//console   修改了name属性
person.name = '帅哥'

1.2、Object.defineProperty的缺点

  • 1、通过上面可以看到,Object.defineProperty()只能监听一个属性的变化,如果要监听多个属性的变化,只能使用Object.keys(obj)进行遍历
let person = {
    name:'万人',
    age:18,
    address:'广州'
}
//设置一个中转函数
function Observer(obj){
    Object.keys(obj).forEach((key)=>{
        defineProperty(obj,key,obj[key])
    })
}

//对多个属性进行监听
function defineProperty(obj,key,value){
    Object.defineProperty(obj,key,{
        get(){
            console.log(`访问了${key}属性`);
            return value
        },
        set(val){
            console.log(`修改了${key}属性`)
            value = val
        }   
    })
}
//对person上的属性进行监听
Observer(person)

//console   访问了name属性
//console    万人
console.log(person.name)
  • 上面的例子可以看得出很麻烦,而且需要设置于一个中转函数

  • 2、当对象中还嵌套了一个对象的时候,如果嵌套的对象中的属性发生了变化,Object.defineProperty同样也无法监听出来。如果想深度监听一个对象,我们就得设置递归

let person = {
    name: '万人',
    age: 18,
    address: '广州',
    school: {
        schoolName: '家里蹲',
        schoolAddress: '家里'
    }
}
//设置一个中转函数
function Observer(obj) {
    //如果传入的不是一个对象,return 
    if (Object.prototype.toString.call(value).slice(8, -1) !== 'Object') {
        Observer(value)
    }

    Object.keys(obj).forEach((key) => {
        defineProperty(obj, key, obj[key])
    })
}

//对多个属性进行监听
function defineProperty(obj, key, value) {
    //如果对象的属性也是一个对象,递归进入该函数,进行监听
    if (Object.prototype.toString.call(value).slice(8, -1) === 'Object') {
      
        Observer(value)
    }
    Object.defineProperty(obj, key, {
        get() {
            console.log(`访问了${key}属性`);
            return value
        },
        set(val) {
            console.log(`修改了${key}属性`)
            value = val
        }
    })
}
//对person上的属性进行监听
Observer(person)

//console   修改了name属性
//console   访问了name属性
person.school.schoolName = 'wr'


  • 3、Object.defineProperty也无法原生监听到数组

  • 4、Object.defindeProperty也无法监听到对象新增属性/删除属性

2、Proxy

  • vue3中使用了proxy,就可以很好解决上面的问题了

  • 基本语法:

  • const obj = new Proxy(target,handler)

  • 被代理后返回的对象 = new Proxy(被代理对象,要代理对象的操作)

  • 常用方法:

  • get(target, propKey, receiver)

  • set(target, propKey, value, receiver),要返回一个布尔值

  • has(target,propKey):拦截propKey in proxy的操作,返回一个布尔值

  • deleteProperty(target,propKey):拦截delete proxy[propKey]的操作,返回一个布尔值

  • construct(target, args):

  • apply(target, object, args)

  • 示例:

let person = {
    name: '万人',
    age: 18,
    address: '广州',
    school: {
        schoolName: '家里蹲',
        schoolAddress: '家里'
    }
}

let handler = {
    get(obj,key){
        console.log(`访问了${key}属性`);
        return key in obj ? obj[key] : '不存在该属性'
    },
    set(obj,key,value){
        console.log(`修改了${key}属性`);
        obj[key] = value
        return true
    }
}

let proxyPerson = new Proxy(person,handler)

//console 访问了name属性
//console 万人
console.log(proxyPerson.name)

//console 修改了address属性
proxyPerson.address = '北京'

  • 可以看出,proxy代理的是整个对象,而不是对象的某个特定属性,不需要我们通过遍历来逐个进行数据绑定
  • 如果要进行深度监听,同样像上面一样加一个递归就好
  • 同时proxy还可以对数组进行监听了
  • 可以看出proxy对Object.defineProperty进行了很大的优化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值