持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情
前言
我们都知道vue2中的响应式是通过Object.defineProperty的get和set函数实现的。但是在vue3中对于对象的响应式(reactive)却是通过ES6的新增对象proxy,它与Object.defineProperty究竟有什么区别?他的作用又有什么?
什么是Proxy
Proxy对象可以理解为在目标对象之前架设一层“拦截器”。通过英文意思[代理]也可以得出,它是目标对象的代理对象,来处理对于目标对象的某些操作。就是说,对于目标对象的操作需要先通过代理对象。所以,我们可以通过Proxy对象来对目标对象的访问进行过滤与改写。
Proxy的语法
var proxy = new Proxy(target, handler);
proxy表示生成的Proxy实例对象
target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截操作行为。
下面是 Proxy 支持的拦截操作一览,一共 13 种。
- get(target, propKey, receiver) :拦截对象属性的读取,比如
proxy.foo和proxy['foo']。 - set(target, propKey, value, receiver) :拦截对象属性的设置,比如
proxy.foo = v或proxy['foo'] = v,返回一个布尔值。 - has(target, propKey) :拦截
propKey in proxy的操作,返回一个布尔值。 - deleteProperty(target, propKey) :拦截
delete proxy[propKey]的操作,返回一个布尔值。 - ownKeys(target) :拦截
Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。 - getOwnPropertyDescriptor(target, propKey) :拦截
Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 - defineProperty(target, propKey, propDesc) :拦截
Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。 - preventExtensions(target) :拦截
Object.preventExtensions(proxy),返回一个布尔值。 - getPrototypeOf(target) :拦截
Object.getPrototypeOf(proxy),返回一个对象。 - isExtensible(target) :拦截
Object.isExtensible(proxy),返回一个布尔值。 - setPrototypeOf(target, proto) :拦截
Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 - apply(target, object, args) :拦截 Proxy 实例作为函数调用的操作,比如
proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。 - construct(target, args) :拦截 Proxy 实例作为构造函数调用的操作,比如
new proxy(...args)。
可以看到,相比于Object.defineProperty的get和set的拦截操作,proxy提供了更多拦截操作去实现更复杂的逻辑应用。
Proxy的应用
get与set
get方法在读取对象的属性时触发。get方法有三个参数,target:目标对象,propKey:读取的属性值,receiver:实例化Proxy对象本身。receiver为可选参数。
const a = {
name: 'Alan',
age: 24,
hobby: 'play'
}
const p = new Proxy(a, {
get(target, propKey, receiver) {
console.log(target, propKey, receiver)
return target[propKey]
}
})
p.age //{name: 'Alan', age: 24, hobby: 'play'}age: 24hobby: "play"name: "Alan"[[Prototype]]: Object 'age' Proxy {name: 'Alan', age: 24, hobby: 'play'}
set方法在赋值对象某个属性时触发。set方法相比于get多了value一个所赋的值。
const a = {
name: 'Alan',
age: 24,
hobby: 'play'
}
const p = new Proxy(a, {
set(target, propKey, value, receiver) {
console.log(target, propKey, value, receiver)
target[propKey] = value
return true
}
})
p.age = 26//{name: 'Alan', age: 24, hobby: 'play'}age: 24hobby: "play"name: "Alan"[[Prototype]]: Object 'age' Proxy {name: 'Alan', age: 24, hobby: 'play'}
console.log(a.age) //26
deleteProperty
deleteProperty方法在delete对象某个属性时触发。传入两个参数,一个是目标对象,一个是属性名。
const p = new Proxy(a, {
deleteProperty(target, propKey) {
console.log(target, propKey)
delete target[propKey]
return true
}
})
delete p.name//{name: 'Alan', age: 24, hobby: 'play'} 'name'
console.log(a.name) //undefined
对于拦截方法的使用就说明到这里,大家感兴趣的话可以自己试一试其他的方法。
总结
对于Es6 Proxy的讲解就是这么多了,学完之后相信大家对于vue3的响应式处理也会有一定的了解,希望大家能有所收获!