JavaScript 之 Proxy
前言
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
语法
Proxy 对象的所有用法,都是上面这种形式,不同的只是 handler 参数的写法。其中:
new Proxy()
表示生成一个 Proxy 实例target 参数表示所要拦截的目标对象
handler 参数也是一个对象,用来定制拦截行为
如果 handler 没有设置任何拦截,那就等同于直接通向原对象。
还有一个技巧是将 Proxy 对象,设置到 object.proxy
属性,从而在 object 对象上调用:
get()
get() 方法用于拦截某个属性的读取操作,可以接受三个参数,依次为:
目标对象
属性名
proxy 实例本身(严格地说,是操作行为所针对的对象),可选。
get()
方法的用法,上文已经有一个例子,下面是另一个拦截读取操作的例子:
set()
set()
方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为:
目标对象
属性名
属性值
Proxy 实例本身,可选。
假定 person 对象有一个 age 属性,该属性应该是一个不大于 200 的整数,那么可以使用 Proxy 保证 age 的属性值符合要求。
apply()
apply()
方法拦截:
函数的调用
call 操作
apply 操作
apply()
方法可以接受三个参数,分别是:
目标对象
目标对象的上下文对象(this)
目标对象的参数数组。
另外,直接调用 Reflect.apply 方法,也会被拦截。
has()
has()
方法用来拦截 HasProperty 操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是 in 运算符。
has()
方法可以接受两个参数,分别是目标对象、需查询的属性名。
下面的例子使用 has 方法隐藏某些属性,不被 in 运算符发现。
上面代码中,has 拦截只对 in 运算符生效,对 for...in
循环不生效,导致不符合要求的属性没有被 for...in 循环所排除。
Proxy 支持的拦截操作一览
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)
。
~
~ 本文完,感谢阅读!
~
学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!
版权声明: 本文为 InfoQ 作者【编程三昧】的原创文章。
原文链接:【http://xie.infoq.cn/article/fd89a64d71187d11d24511692】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论