Proxy;Reflect;捕获trap;捕获器不变式;代理的应用;
疑问:
- 代理到底有什么用?
- 开源库中应该用得更多,日常开发的应用较少,适合做各种数据的批量监控与管理。
- 代理和C++指针的区别是?
-
心得&书摘:
1 代理基础
定义
代理是目标对象的抽象
- 类似C++的指针
- 既可以当成对象的替身,又完全独立于对象
- 然而还是存在重大区别的
代理是使用Proxy构造函数创建的
const proxy = new Proxy(target, handler);
在代理对象上执行的任何操作实际上都会应用到目标对象
可撤销代理
使用代理的主要目的是可以定义捕获器(trap)
- 原来英文是trap,难怪有的资料翻译为陷阱
- 基本操作拦截器
- 当通过代理对象执行get()操作时,就会触发定义的get()捕获器,从而在中间执行各种操作,甚至改变返回值。
但是,捕获处理程序的行为必须遵循“捕获器不变式”(trap invariant)
所有捕获器都可以基于自己的参数重建原始操作,但并非所有捕获器行为都像get()那么简单。因此,通过手动写码如法炮制的想法是不现实的。
- 调用全局Reflect对象上(封装了原始行为)的同名方法来轻松重建。
- 各种花式重建 ```javascript // 老老实实 const handler = { get() { return Reflect.get(…arguments); } };
// 没啥意思 const handler = { get: Reflect.get };
// 何必? const proxy = new Proxy(target, Reflect); ```
Reflect
- 最常用的地方就是上述的代理重建。
相比对象API,某些情况下应该优先使用反射API
- 标记状态:以下反射API会告知操作成功与否
- ❑ Reflect.defineProperty()
- ❑ Reflect.preventExtensions()
- ❑ Reflect.setPrototypeOf()
- ❑ Reflect.set()
- ❑ Reflect.deleteProperty()
- 代替一等函数:以下反射方法提供只有通过操作符才能完成的操作
- ❑ Reflect.get():可以替代对象属性访问操作符。
- ❑ Reflect.set():可以替代=赋值操作符。
- ❑ Reflect.has():可以替代in操作符或with()。
- ❑ Reflect.deleteProperty():可以替代delete操作符。
- ❑ Reflect.construct():可以替代new操作符。
- 安全地应用函数
- 在通过apply方法调用函数时,被调用的函数可能也定义了自己的apply属性
- Reflect.apply(myFunc, thisVal, argumentsList)
- 代理另一个代理
- 标记状态:以下反射API会告知操作成功与否
this指向
- 书中与weakMap联合讲解了一下,过于深奥不做研究【四?】
代理与内部槽位
get()
- get()捕获器会在获取属性值的操作中被调用。
- 对应的反射API方法为Reflect.get()。
- 返回值:无限制
- 拦截的操作:
- ❑ proxy.property
- ❑ proxy[property]
- ❑ Object.create(proxy)[property]
- ❑ Reflect.get(proxy, property, receiver)
- set()
- set()捕获器会在设置属性值的操作中被调用。
- 对应的反射API方法为Reflect.set()。
- 返回值:布尔值
- 拦截的操作:
- ❑ proxy.property = value
- ❑ proxy[property] = value
- ❑ Object.create(proxy)[property] = value
- ❑ Reflect.set(proxy, property, value, receiver)
- has()
- has()捕获器会在in操作符中被调用。
- 对应的反射API方法为Reflect.has()。
- 返回值:布尔值,属性是否存在
- 拦截的操作
- ❑ property in proxy
- ❑ property in Object.create(proxy)
- ❑ with(proxy) {(property); }
- ❑ Reflect.has(proxy, property)
- defineProperty()
- defineProperty()捕获器会在Object.defineProperty()中被调用。
- 对应的反射API方法为Reflect.defineProperty()。
- 返回值:布尔值
- 拦截的操作
- ❑ Object.defineProperty(proxy, property, descriptor)
- ❑ Reflect.defineProperty(proxy, property, descriptor)
-
3 代理模式——代理的应用
1、跟踪属性访问
监控对象
通过定义一个统一的构造函数,实现在创建代理时将创建的对象收集起来
- 每次插入新实例时都会发送消息
6、做对象属性的批量修改,无视属性名
比如批量修改接口返回值数据,可以做到不关心具体属性名,对对象的所有属性做统一处理:
摘自阮一峰《ES6 入门教程》:https://es6.ruanyifeng.com/7、为所欲为
**