监听方式
Object.defineProperty
Object.defineProperty
只能劫持对象的某一个属性,不能对整个对象进行劫持,如果需要监听某一个对象的所有属性,需要遍历对象的所有属性并对其进行劫持来进行监听。
const data = {
a: 1,
b: 2
};
Object.keys(data).forEach(key => {
let oldValue = data[key]
Object.defineProperty(data, key, {
get() {
console.log('get')
return oldValue
},
set(value) {
console.log('set')
oldValue = value
}
})
})
console.log(data.a) // 1
data.b = 3
console.log(data.b) // 3
console.log(data) // { a: 1, b: 3 }
Proxy
const data = {
a: 1,
b: 2
};
const proxyData = new Proxy(data, {
get(target, prop) {
console.log('get')
return Reflect.get(target, prop)
},
set(target, prop, value) {
console.log('set')
return Reflect.set(target, prop, value) // Reflect通过代理对象更改目标对象的属性值
}
})
console.log(data.a) // 1
console.log(proxyData.a) // 1
data.a = 2
console.log(data.a) // 2
console.log(proxyData.a) // 2
proxyData.b = 3
console.log(data.b) // 3
console.log(proxyData.b) // 3
console.log(data) // { a: 1, b: 3 }
console.log(proxyData) // { a: 1, b: 3 }
设置代理对象的属性后,原始对象和代理对象都发生了变化,但是获取原始对象的属性不会触发getter
,只有访问代理对象的属性才能触发getter
。
监听属性新增
data.c = 3;
Object.defineProperty
对象新增属性的时候,Object.defineProperty
没有对新增的属性进行劫持,监听不到对象属性的新增。
Proxy
proxy
是对整个对象进行代理,能监听到对象属性的新增。
监听属性删除
Object.defineProperty
无法监听对象删除属性
Proxy
proxy
有专门针对属性删除的方法deleteProperty
,可以在对象属性被删除时触发。
const data = {
a: 1,
b: 2
};
const proxyData = new Proxy(data, {
get(target, prop) {
console.log('get')
return Reflect.get(target, prop)
},
set(target, prop, value) {
console.log('set')
return Reflect.set(target, prop, value) // Reflect通过代理对象更改目标对象的属性值
},
deleteProperty(target, prop) {
console.log('delete')
Reflect.deleteProperty(target, prop)
return true
}
})
delete proxyData.b
console.log(data)
监听数组修改
Object.defineProperty
无法监听到数组修改;但是Vue2中重写了push
、pop
、shift
、unshift
、splice
、sort
、reverse
这七个数组方法,以达到监听的目的。但依然存在以下标方式修改数组值时响应式失效的情况,针对整个问题也提供了$set
方法,即:this.$set(arr,index,value)
。
Proxy
proxy
可以监听到数组修改,且不需要$set
函数以及重写数组方法。
性能
Object.defineProperty
通过循环遍历对象属性的方式来进行监听,耗性能。
Proxy
一次对整个对象进行监听,另外 Proxy 的拦截也是懒处理行为,如果没有访问嵌套对象,那么也不会实施拦截,这就让初始化的速度和内存占用都改善了。