Object.defineProperty可以监听属性读写。Proxy是为对象设置访问代理器。
两者都可以用来设置监听,在vue2.0中使用Object.defineProperty进行数据监听,而在vue3.0中改用Proxy,两者有什么区别,又是什么原因促使vue作出如此变更呢?
一 Proxy使用
Proxy是一个类,通过new返回实例的方式来调用。
创建实例时它的构造函数接受两个参数,目标对象和监控对象,目标对象是要进行监控的对象,监控对象是用来配置监控行为的对象,可以设置get,set等属性。
1.1 get:访问操作
当访问proxy实例时,会访问监控对象的get,并传入两个参数,目标对象和访问的属性名。
const person = {
name: 'kk',
age: 23
}
const personProxy = new Proxy(person, {
get(target, property){
console.log(target, property) // { name: 'kk', age: 23 } name
return 100
},
set(){}
})
console.log(personProxy.name) // 100
这里可以通过get对属性设置默认值。
const personProxy = new Proxy(person, {
get(target, property){
return property in target? target[property]: 'default'
},
set(){}
})
console.log(personProxy.name) // kk
console.log(personProxy.a) // default
如上,在通过get获取值时根据目标对象和访问属性,可以取到实际值,经过运算后将处理后的值return抛出,return的值就是调用实例中取到的值。
1.2 set:赋值操作
当写入proxy实例时,会访问监控对象中配置的set,并传入三个参数,为目标对象和访问的属性名,和写入值。
const personProxy = new Proxy(person, {
...
set(target, property,value){
console.log(target, property,value) // { name: 'kk', age: 23 } name 1
}
})
personProxy.name = 1
可以在set中设置数据校验。
const personProxy = new Proxy(person, {
...
set(target, property, value){
if(property === 'age'){
if(!Number.isInteger(value)){
throw Error(value + 'is error')
}
}else {
target[property] = value
}
}
})
二 Proxy优势
2.1 监控更加全面
除了get, set,proxy还有很多其他方法监控其他操作,如delete监控。
const personProxy = new Proxy(person, {
...
deleteProperty(target, property){
console.log(target, property)
}
})
delete personProxy.age // { name: 'kk', age: 23 } age
2.2 支持数组监视
Object.defineProperty无法对数组进行监视,vue2.0通过重写数组操作方法的方式进行监视。
而proxy可以直接监视数组。
如下,对一个数组设置代理后,对代理运行的push、pop等方法都会转化为set和delete操作,反应在监控对象上。
const person = []
const listProxy = new Proxy(person, {
set(target, property, value){
console.log('set', target, property, value)
target[property] = value
return true // 设置成功
},
deleteProperty(target, property){
console.log('del', target, property)
return true
}
})
listProxy.push(100)
//set [] 0 100
//set [ 100 ] length 1
listProxy.push(200)
//set [ 100 ] 1 200
//set [ 100, 200 ] length 2
listProxy.pop()
//del [ 100, 200 ] 1
//set [ 100, 200 ] length 1
2.3 非侵入式监视
proxy是非侵入的模式监视内部读写。不需要单独对属性设置。
指的一提的是,proxy仍然未实现深度监听,需要通过递归代理的方式监听。