简介
Proxy
可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy
这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
一个简单的例子
let obj = new Proxy({}, {
get(target, key, receiver) {
console.log(`getting ${key}!`)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
console.log(`setting ${key}!`)
return Reflect.set(target, key, value, receiver)
}
})
obj.count = 1
// setting count!
++obj.count
// getting count!
// setting count!
// 2
这就实现了对 obj
对象操作时的拦截,换句话说就是:proxy
为开发者提供更加细粒化对数据的操作,使得开发者可以介入对数据的操作,在不改变原有操作的情况下修改数据流程。
写法
let proxy = new Proxy(target, handler);
- target 目标对象
- handler 需要对对象进行代理的行为合集
使用
属性拦截
let proxy = new Proxy({}, {
get(target, property) {
return 35;
}
});
proxy.time // 35
proxy.name // 35
proxy.title // 35
通过 proxy
的介入,使得对于任何属性的访问都返回特定值,当然也可以自定规则。
不设拦截
let target = {}
let handler = {}
let proxy = new Proxy(target, handler)
proxy.a = 'b'
target.a
// "b"
当不拦截对象(也就是代理行为为空)时,对代理对象的操作可以认为是对原对象进行操作。
其实更深入的了解应该是:默认的代理行为和对象的原始操作一致,当某个代理行为为空时,就是默认的行为,而不是空。
常用的行为
参数统一解释:
参数名 | 作用 |
---|---|
target |
被代理的对象(也就是原始对象) |
propKey |
访问的键值 |
value |
设置的属性值 |
receiver |
提供者,查看注一 |
propDesc |
设置的某个对象属性的描述 |
proto |
设置的某个对象的原型 |
object |
设置的函数执行上下文 |
args |
传入的函数参数 |
- 注一 提供者,比如当访问
proxy.foo
时,receiver
即为proxy
,大多数情况是代理对象本身,但如果代理对象(A
)是某个对象(B
)的原型的话,当A
通过原型链访问到B
时,receiver 为A
。
可以使用的拦截,一共有 13 种,如下
拦截方法名 | 作用 |
---|---|
get(target, propKey, receiver) |
拦截对象属性的读取,返回值。eg: proxy.foo |
set(target, propKey, value, receiver) |
拦截对象属性的设置。 eg: proxy.foo = 1 |
has(target, propKey) |
拦截对象的 in 操作,返回布尔值。 eg: foo in proxy |
deleteProperty(target, propKey) |
拦截 delete 操作,返回布尔值。 eg: delete proxy.foo |
ownKey(taget) |
拦截对对象的取值列表操作(注一),返回一个数组 |
getOwnPropertyDescriptor(target, propKey) |
拦截 Object.getOwnPropertyDescriptor ,返回属性的描述对象。 |
defineProperty(target, propKey, propDesc) |
拦截 Object.defineProperty[s] ,返回布尔值 |
getPrototypeOf(target) |
拦截 Object.getPrototypeOf(proxy) ,返回一个对象。 |
setPrototypeOf(target, proto) |
拦截 Object.setPrototypeOf(proxy, 'foo') ,返回布尔值。 |
apply(target, object, args) |
拦截函数的绑定执行上下文的行为,包括函数的调用、 call 和 apply 操作。 |
- 注一 拦截对象的取值:包括
Object.getOwnPropertyNames(proxy)
、Object.getOwnPropertySymbols(proxy)
、Object.keys(proxy)
、for...in
具体代理行为的表现可以去看阮老师的 Proxy 中的具体内容。
可被取消的代理 Proxy.revocable()
Proxy.revocable
方法返回一个可取消的Proxy
实例。
let target = {}
let handler = {}
let {proxy, revoke} = Proxy.revocable(target, handler)
proxy.foo = 123
proxy.foo // 123
revoke()
proxy.foo // TypeError: Revoked
函数返回一个代理对象和取消方法,当执行取消方法时,代理即会被销毁。
注: 上面的例子大多数来自《ECMAScript 6入门》这本书。