一、proxy概述
Proxy的兼容性

proxy在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截
var proxy = new Proxy(target, handler); |
new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为
var target = { |
targetWithLog读取属性的值时,实际上执行的是logHandler.get:在控制台输出信息,并且读取被代理对象target的属性。- 在
targetWithLog设置属性值时,实际上执行的是logHandler.set:在控制台输出信息,并且设置被代理对象target的属性的值
// 由于拦截函数总是返回35,所以访问任何属性都得到35 |
Proxy 实例也可以作为其他对象的原型对象
var proxy = new Proxy({}, { |
proxy对象是obj对象的原型,obj对象本身并没有time属性,所以根据原型链,会在proxy对象上读取该属性,导致被拦截
Proxy的作用
对于代理模式
Proxy的作用主要体现在三个方面
- 拦截和监视外部对对象的访问
- 降低函数或类的复杂度
- 在复杂操作前对操作进行校验或对所需资源进行管理
二、Proxy所能代理的范围–handler
实际上
handler本身就是ES6所新设计的一个对象.它的作用就是用来 自定义代理对象的各种可代理操作 。它本身一共有13中方法,每种方法都可以代理一种操作.其13种方法如下
// 在读取代理对象的原型时触发该操作,比如在执行 Object.getPrototypeOf(proxy) 时。 |
三、Proxy场景
3.1 实现私有变量
var target = { |
在下面的代码中,我们声明了一个私有的
apiKey,便于api这个对象内部的方法调用,但不希望从外部也能够访问api._apiKey
var api = { |
很显然,约定俗成是没有束缚力的。使用
ES6 Proxy我们就可以实现真实的私有变量了,下面针对不同的读取方式演示两个不同的私有化方法。第一种方法是使用set / get拦截读写请求并返回undefined:
let api = { |
第二种方法是使用
has拦截in操作
var api = { |
3.2 抽离校验模块
让我们从一个简单的类型校验开始做起,这个示例演示了如何使用
Proxy保障数据类型的准确性
let numericDataStore = { |
如果要直接为对象的所有属性开发一个校验器可能很快就会让代码结构变得臃肿,使用
Proxy则可以将校验器从核心逻辑分离出来自成一体
function createValidator(target, validator) { |
通过校验器和主逻辑的分离,你可以无限扩展
personValidators校验器的内容,而不会对相关的类或函数造成直接破坏。更复杂一点,我们还可以使用Proxy模拟类型检查,检查函数是否接收了类型和数量都正确的参数
let obj = { |
3.3 访问日志
对于那些调用频繁、运行缓慢或占用执行环境资源较多的属性或接口,开发者会希望记录它们的使用情况或性能表现,这个时候就可以使用
Proxy充当中间件的角色,轻而易举实现日志功能
let api = { |
3.4 预警和拦截
假设你不想让其他开发者删除
noDelete属性,还想让调用oldMethod的开发者了解到这个方法已经被废弃了,或者告诉开发者不要修改doNotChange属性,那么就可以使用Proxy来实现
let dataStore = { |
3.5 过滤操作
某些操作会非常占用资源,比如传输大文件,这个时候如果文件已经在分块发送了,就不需要在对新的请求作出相应(非绝对),这个时候就可以使用
Proxy对当请求进行特征检测,并根据特征过滤出哪些是不需要响应的,哪些是需要响应的。下面的代码简单演示了过滤特征的方式,并不是完整代码,相信大家会理解其中的妙处
let obj = { |
3.6 中断代理
Proxy支持随时取消对target的代理,这一操作常用于完全封闭对数据或接口的访问。在下面的示例中,我们使用了Proxy.revocable方法创建了可撤销代理的代理对象:
let sensitiveData = { username: 'devbryce' }; |