• ECMAScript 6 Reflect / Proxy


    基础

    Reflect

    建议先看 Reflect 然后再看 Proxy。该对象用于拦截 JavaScript 操作的方法。

    示例代码参考: https://www.javascripttutorial.net/es6/javascript-reflection/

    在了解了 Reflect 和 Proxy 之后,还可以再深入了解一下 React.metadata: reflect-metadata

    Proxy

    代理是可以实现拦截和自定义的。

    示例代码参考: https://www.javascripttutorial.net/es6/javascript-proxy/

    实用指南: https://blog.bitsrc.io/a-practical-guide-to-es6-proxy-229079c3c2f0

    Demo

    const axios = require('axios');
    
    
    
    const SDK = (options) => {
    
      const client = axios.create(options);
    
      return new Proxy(
    
        {},
    
        {
    
          get: (_, property) => client[property.toLowerCase()]
    
        }
    
      );
    
    };
    
    
    
    const client = SDK({
    
      baseURL: 'https://api.xxxx.com',
    
      timeout: 1000,
    
      headers: {
    
        'X-Custom-Header': 'foobar'
    
      }
    
    });
    
    
    
    // Use just like axios:
    
    client.get('/xxx').then();
    
    
    
    client
    
      .post('/xxx', {
    
        // form body
    
      })
    
      .then();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    问题

    TypeError

    不规范的使用会导致报错,并且该方式的调用无法被捕获

    const p = new Proxy(
    
      {},
    
      {
    
        get: (target, property, receiver) => {
    
          console.log(target, property, receiver);
    
          try {
    
            return property;
    
          } catch (e) {
    
            console.log(e.message);
    
            return '';
    
          }
    
        }
    
      }
    
    );
    
    
    
    console.log(p.test);
    
    console.log(p.test());
    
    
    
    /*
    
    {} test {}
    
    test
    
    {} test {}
    
    /Users/v0/Projects/Authing/demos/proxy-sdk/index.js:17
    
    console.log(p.test());
    
                  ^
    
    
    
    TypeError: p.test is not a function
    
        at Object. (/Users/v0/Projects/Authing/demos/proxy-sdk/index.js:17:15)
    
        at Module._compile (node:internal/modules/cjs/loader:1101:14)
    
        at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    
        at Module.load (node:internal/modules/cjs/loader:981:32)
    
        at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    
        at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    
        at node:internal/main/run_main_module:17:47
    
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    如果这样写的话:

    const p = new Proxy(
    
      {},
    
      {
    
        get: (target, property, receiver) => {
    
          console.log(target, property, receiver);
    
          return () => property;
    
        }
    
      }
    
    );
    
    
    
    console.log(p.test);
    
    console.log(p.test());
    
    /*
    
    {} test {}
    
    [Function (anonymous)]
    
    {} test {}
    
    test
    
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    虽然不会报错,但是强制了返回为 Function。如果想要更灵活的运用,则不能仅使用空对象进行扩展,需要配合 set 去针对性设置某些 property

    示例:

    const p = new Proxy(
    
      {},
    
      {
    
        construct: (target) => {},
    
        get: (target, property, receiver) => {
    
          console.log(target, property, receiver);
    
          // 注入的方法
    
          if (target.hasOwnProperty(property)) {
    
            return target[property];
    
          }
    
          return () => property;
    
        }
    
      }
    
    );
    
    
    
    // 简单的方法之一: 配合 Reflect 使用
    
    Reflect.set(p, 'test', 'test1');
    
    
    
    console.log(p.test);
    
    console.log(p.test2());
    
    /*
    
    { test: 'test1' } test { test: 'test1' }
    
    test1
    
    { test: 'test1' } test2 { test: 'test1' }
    
    test2
    
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    简单示例

    可以配合使用 Reflect Metadata 来注入拦截。比如说创建 Before Hook、 After Hook 等。

    // import 'reflect-metadata';
    
    require('reflect-metadata');
    
    
    
    const p = new Proxy(
    
      {},
    
      {
    
        construct: (target) => {},
    
        get: (target, property, receiver) => {
    
          const injected = Reflect.getMetadata('before', p, property);
    
          if (injected) injected();
    
          if (target.hasOwnProperty(property)) {
    
            return target[property];
    
          }
    
          return () => property;
    
        }
    
      }
    
    );
    
    
    
    Reflect.defineMetadata(
    
      'before',
    
      () => {
    
        console.log('BeforeEach');
    
      },
    
      p,
    
      'test'
    
    );
    
    
    
    console.log(p.test());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    Refs

  • 相关阅读:
    我觉得还挺好懂的meta learning 元学习总结
    ubuntu20 安装 cmake 3.27
    Unity中Shader阴影的投射
    React 使用 Zustand 详细教程
    java8 线程
    【Spring】——8、如何使用FactoryBean向Spring容器中注册bean?
    基于SpringBoot Vue宠物领养系统
    vivo数据中心网络链路质量监测的探索实践
    JVM P1 整体架构,类加载器,运行时数据区
    程序员面试金典 - 面试题 17.12. BiNode
  • 原文地址:https://blog.csdn.net/jslygwx/article/details/126064970