使用代理可以在代码中实现一些有用的编程模式。
    9.3.1 跟踪属性访问
    通过捕获get、set和has等操作,可以知道对象属性什么时候被访问、被查询。
    把实现相应捕获器的某个对象代理放到应用中,可以监控这个对象何时在何处被访问过:

    1. const user = {
    2. name: 'Jack'
    3. };
    4. const proxy = new Proxy(user, {
    5. get(target, property, receiver) {
    6. console.log(`获取 ${property}`);
    7. return Reflect.get(...arguments);
    8. },
    9. set(target, property, value, receiver) {
    10. console.log(`设置 ${property} = ${value}`);
    11. return Reflect.set(...arguments);
    12. }
    13. });
    14. proxy.name;
    15. proxy.age = 27;
    16. // 获取 name
    17. // 设置 age = 27

    9.3.2 隐藏属性
    代理的内部实现对外部代码是不可见的,因此要隐藏目标对象上的属性也轻而易举。
    比如:

    1. const hiddenProperties = ['foo', 'bar'];
    2. const targetObject = {
    3. foo: 1,
    4. bar: 2,
    5. baz: 3
    6. };
    7. const proxy = new Proxy(targetObject, {
    8. get(target, property) {
    9. if (hiddenProperties.includes(property)) {
    10. return undefined;
    11. } else {
    12. return Reflect.get(...arguments);
    13. }
    14. },
    15. set(target, property) {
    16. if (hiddenProperties.includes(property)) {
    17. return false;
    18. } else {
    19. return Reflect.has(...arguments);
    20. }
    21. }
    22. });
    23. // get()
    24. console.log(proxy.foo); // undefined
    25. console.log(proxy.bar); // undefined
    26. console.log(proxy.baz); // 3
    27. // set()
    28. console.log('foo' in proxy); // true
    29. console.log('bar' in proxy); // true
    30. console.log('baz' in proxy); // true

    9.3.3 属性验证
    因为所有赋值操作都会触发set()捕获器,所以可以根据所赋的值决定是允许还是拒绝赋值:

    1. const target = {
    2. onlyNumbersGoHere: 0
    3. };
    4. const proxy = new Proxy(target, {
    5. set(target, property, value) {
    6. if (typeof value !== 'number') {
    7. return false;
    8. } else {
    9. return Reflect.set(...arguments);
    10. }
    11. }
    12. });
    13. proxy.onlyNumbersGoHere = 1;
    14. console.log(proxy.onlyNumbersGoHere); // 1
    15. proxy.onlyNumbersGoHere = '2';
    16. console.log(proxy.onlyNumbersGoHere); // 1

    9.3.4 函数与构造函数参数验证
    跟保护和验证对象属性类似,也可对函数和构造函数参数进行审查。
    比如,可以让函数只接收某种类型的值
    9.3.5 数据绑定与可观察对象
    通过代理可以把运行时中原本不相关的部分联系到一起。这样就可以实现各种模式,从而让不同的代码互操作。
    比如,可以将被代理的类绑定到一个全局实例集合,让所有创建的实例都被添加到这个集合中.
    另外,还可以把集合绑定到一个事件分派程序,每次插入新实例时都会发送消息
    9.4 小结
    代理是ECMAScript 6新增的新特性。不支持向后兼容。
    从宏观上看,代理是真实JavaScript对象的透明抽象层。
    代理可以定义包含捕获器的处理程序对象,而这些捕获器可以拦截绝大部分JavaScript的基本操作和方法。
    在这个捕获器处理程序中,可以修改任何基本操作的行为,当然前提是遵从捕获器不变式。
    与代理如影随形的反射API,则封装了一整套与捕获器拦截的操作相对应的方法。
    可以把反射API看作一套基本操作,这些操作是绝大部分JavaScript对象API的基础。
    代理的应用场景是不可限量的。开发者使用它可以创建出各种编码模式,比如(但远远不限于)跟踪属性访问、隐藏属性、阻止修改或删除属性、函数参数验证、构造函数参数验证、数据绑定,以及可观察对象。