• ES6 入门教程 15 Proxy 15.3 Proxy.revocable() & 15.4 this 问题 & 15.5 实例:Web 服务的客户端


    ES6 入门教程

    ECMAScript 6 入门

    作者:阮一峰

    本文仅用于学习记录,不存在任何商业用途,如侵删

    15 Proxy

    15.3 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述

    Proxy.revocable()方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例。上面代码中,当执行revoke函数之后,再访问Proxy实例,就会抛出一个错误。

    Proxy.revocable()的一个使用场景是,目标对象不允许直接访问,必须通过代理访问,一旦访问结束,就收回代理权,不允许再次访问。

    15.4 this 问题

    虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证与目标对象的行为一致。

    主要原因就是在 Proxy 代理的情况下,目标对象内部的this关键字会指向 Proxy 代理。

    const target = {
      m: function () {
        console.log(this === proxy);
      }
    };
    const handler = {};
    
    const proxy = new Proxy(target, handler);
    
    target.m() // false
    proxy.m()  // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    上面代码中,一旦proxy代理targettarget.m()内部的this就是指向proxy,而不是target。所以,虽然proxy没有做任何拦截,target.m()proxy.m()返回不一样的结果。

    下面是一个例子,由于this指向的变化,导致 Proxy 无法代理目标对象。

    const _name = new WeakMap();
    
    class Person {
      constructor(name) {
        _name.set(this, name);
      }
      get name() {
        return _name.get(this);
      }
    }
    
    const jane = new Person('Jane');
    jane.name // 'Jane'
    
    const proxy = new Proxy(jane, {});
    proxy.name // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    上面代码中,目标对象janename属性,实际保存在外部WeakMap对象_name上面,通过this键区分。由于通过proxy.name访问时,this指向proxy,导致无法取到值,所以返回undefined

    此外,有些原生对象的内部属性,只有通过正确的this才能拿到,所以 Proxy 也无法代理这些原生对象的属性。

    const target = new Date();
    const handler = {};
    const proxy = new Proxy(target, handler);
    
    proxy.getDate();
    // TypeError: this is not a Date object.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    上面代码中,getDate()方法只能在Date对象实例上面拿到,如果this不是Date对象实例就会报错。这时,this绑定原始对象,就可以解决这个问题。

    const target = new Date('2015-01-01');
    const handler = {
      get(target, prop) {
        if (prop === 'getDate') {
          return target.getDate.bind(target);
        }
        return Reflect.get(target, prop);
      }
    };
    const proxy = new Proxy(target, handler);
    
    proxy.getDate() // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    另外,Proxy 拦截函数内部的this,指向的是handler对象。

    const handler = {
      get: function (target, key, receiver) {
        console.log(this === handler);
        return 'Hello, ' + key;
      },
      set: function (target, key, value) {
        console.log(this === handler);
        target[key] = value;
        return true;
      }
    };
    
    const proxy = new Proxy({}, handler);
    
    proxy.foo
    // true
    // Hello, foo
    
    proxy.foo = 1
    // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    上面例子中,get()set()拦截函数内部的this,指向的都是handler对象。

    15.5 实例:Web 服务的客户端

    Proxy 对象可以拦截目标对象的任意属性,这使得它很合适用来写 Web 服务的客户端。

    const service = createWebService('http://example.com/data');
    
    service.employees().then(json => {
      const employees = JSON.parse(json);
      // ···
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    上面代码新建了一个 Web 服务的接口,这个接口返回各种数据。Proxy 可以拦截这个对象的任意属性,所以不用为每一种数据写一个适配方法,只要写一个 Proxy 拦截就可以了。

    function createWebService(baseUrl) {
      return new Proxy({}, {
        get(target, propKey, receiver) {
          return () => httpGet(baseUrl + '/' + propKey);
        }
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    同理,Proxy 也可以用来实现数据库的 ORM 层。

  • 相关阅读:
    C++ 背包问题——01背包
    java毕业设计保险公司客户信息管理系统Mybatis+系统+数据库+调试部署
    浅谈 -- ♡ ‧₊˚ JS 与JQ的区别 ‧₊˚ ♡
    【Python 实战基础】Pandas如何将表格的前几行生成html
    Datax安装
    《Java 并发编程实战》—— 安全性、活跃性以及性能问题
    minimumLineSpacing和minimumInteritemSpacing问题研究
    IDEA快捷键和模板
    Java面向对象8——抽象类和抽象方法(知识点+使用方法)
    puzzle(021.1)挑选消除问题
  • 原文地址:https://blog.csdn.net/weixin_44226181/article/details/127944926