Open
Description
概念
用于修改某些操作的默认行为,等同于在语言层面做出修改。相当于在目标对象之前架设一层“拦截”,外部对对象的操作,必须通过这层拦截,可对操作进行过滤和改写。
const proxyObject = new Proxy({}, {
get (target, key, receiver) {
// target: 目标对象
// key: 当前获取的键
// receiver: 当前 Proxy 对象
console.log('getting ', key)
return Reflect.get(target, key, receiver)
},
set (target, key, value, receiver) {
// value 当前设置的值
console.log('setting ', key)
return Reflect.set(target, key, value, receiver)
},
})
proxyObject.a = 1 // setting a
proxyObject.a++
// getting a
// setting a
// 1
Proxy 的 13 种拦截操作
get? (target: T, p: PropertyKey, receiver: any): any
拦截属性的读取set? (target: T, p: PropertyKey, value: any, receiver: any): boolean
拦截属性的设置has? (target: T, p: PropertyKey): boolean
拦截propertyKey in proxy
操作deleteProperty? (target: T, p: PropertyKey): boolean
拦截删除属性操作ownKeys? (target: T): PropertyKey[]
拦截Object.getOwnPropertyNames(proxy)
,Object.getOwnPropertySymbols(proxy)
,Object.keys(proxy)
,for...in
getOwnPropertyDescriptor? (target: T, p: PropertyKey): PropertyDescriptor | undefined
拦截Object.getOwnPropertyDescriptor(proxy, propertyKey)
defineProperty? (target: T, p: PropertyKey, attributes: PropertyDescriptor): boolean
拦截Object.defineProperty(proxy, propertyKey, propertyDescriptor)
,Object.defineProperties(proxy, propertyDescriptors)
preventExtensions? (target: T): boolean
拦截Object.preventExtensions(proxy)
getPrototypeOf? (target: T): object | null
拦截Object.getPrototypeOf(proxy)
setPrototypeOf? (target: T, v: any): boolean
拦截Object.setPrototypeOf(proxy, proto)
isExtensible? (target: T): boolean
拦截Object.isExtensible(proxy)
apply? (target: T, thisArg: any, argArray?: any): any
拦截 Proxy 实例作为函数调用的操作construct? (target: T, argArray: any, newTarget?: any): object
拦截 Proxy 实例作为构造函数调用的操作
具体参数说明与用法,可参考各类文档,例如 MDN , typescript 定义,http://es6.ruanyifeng.com/#docs/proxy 等。
Proxy.revocable()
定义:
revocable<T extends object>(target: T, handler: ProxyHandler<T>): { proxy: T; revoke: () => void; }
返回一个可取消的 Proxy 实例
const { proxy, revoke } = Proxy.revocable({}, {})
proxy.a = 1
proxy.a // 1
revoke()
proxy.a // TypeError: Cannot perform 'get' on a proxy that has been revoked
可应用于不允许直接访问对象,必须通过代理访问,访问结束后就收回代理,不能再次访问的场景。
this
Proxy 中的 this 指向的是 proxy ,而不是原对象,因此,即使 handler 是空的,什么也不拦截,其 proxy 的表现与原对象也不是完全一致的。
const target = {
f () {
return this
}
}
const proxy = new Proxy(target, {})
target.f() === target // true
proxy.f() === target // false
proxy.f() === proxy // true
此外,一些原生对象的内部属性,只有通过正确的 this 才能拿到,例如 Date
:
const target = new Date()
const proxy = new Proxy(target, {})
proxy.getDate() // TypeError: this is not a Date object
如果把 this 绑定回原来的对象,就可以正常使用:
const target = new Date()
const proxy = new Proxy(target, {
get (target, key) {
if (key === 'getDate') {
// 判断是否调用的 getDate 方法
return target.getDate.bind(target)
}
return Reflect.get(target, key)
}
})
proxy.getDate() // 正常显示日期