使用非遗留装饰器时如何装饰 JavaScript class 构造函数?

How to decorate a JavaScript class constructor when using non-legacy decorators?

我有以下 class:

@log
class Example {
  constructor(name, age) {
    console.log("Example constructor", name, age);
    this.name = name;
    this.age = age;
  }
}

而这个 @log 装饰器在使用遗留装饰器时:

function log(Class) {
  return class extends Class {
    constructor(...args) {
      console.log("log", args);
      super(...args);
    }
  };
}
// .babelrc
// ...
      "plugins": [
        ["@babel/plugin-proposal-decorators", { "legacy": true }],
        // ...
      ]
// ...

以上设置运行良好,下面的代码:

const example = new Example("Graham", 34);

输出:

log (2) ["Graham", 34]
Example constructor Graham 34

现在,我怎样才能在使用非遗留装饰器时获得相同的结果,即:

// .babelrc
// ...
      "plugins": [
        [
          "@babel/plugin-proposal-decorators",
          { "decoratorsBeforeExport": false }
        ],
        // ...
      ]
// ...

如何实现 @log 以使其与传统装饰器的工作方式相同?

function log(...args) {
  const [descriptor] = args;
  const { kind, elements } = descriptor;

  const newElements = elements.concat({
    kind: "method",
    placement: "prototype",
    key: "constructor",
    descriptor: {
      value: (...args) => {
        // I have tried this but it doesn't work...
        console.log("log", args);
      },
      configurable: true,
      writable: true,
      enumerable: true,
    },
  });

  return {
    kind,
    elements: newElements,
  };
}

我试过上面的代码,但没有用。问题是我在使用非遗留装饰器时没有对目标的引用。您知道是否有办法实现与旧版相同的行为?

谢谢。

我找到了答案,感谢 BabelJS Slack channel 上的 loganfsmyth。

您必须 return 一个带有 属性 的对象 finisher 包裹 class,例如:

function log(...args) {
  const [descriptor] = args;
  const { kind, elements } = descriptor;

  return {
    kind,
    elements,
    finisher: (Class) => {
      return class extends Class {
        constructor(...args) {
          console.log("log", args);
          super(...args);
        }
      };
    }
  };
}

然后使用非遗留装饰器时的代码:

@log
class Example {
  constructor(name, age) {
    console.log("Example constructor", name, age);
    this.name = name;
    this.age = age;
  }
}

const example = new Example("Graham", 34);

输出:

log (2) ["Graham", 34]
Example constructor Graham 34

与遗留装饰器一样。

很难找到答案,因为 @babel/plugin-proposal-decorators.

上没有记录非遗留装饰器的这个特性