将装饰器与 class 构造函数一起使用

Using decorators together with class constructors

我正在尝试在 class 中使用装饰器,该装饰器使用参数进行初始化,但是当装饰器应用于我的函数时,构造函数中设置的值未定义。请看下面的玩具示例:

function someDecorator() {
  return (target: any, _2: any, descriptor: PropertyDescriptor) => {
    const func = descriptor.value.bind(target);
    descriptor.value = () => {
      console.log('Doing decorator stuff!');
      func();
    }
  }
}

class Foo {

  public constructor(private thing: string) { }

  @someDecorator()
  bar() {
    console.log(this.thing);
  }
}

new Foo('Hello world!').bar();

我当然想要输出:

> Doing decorator stuff!
> Hello world!

但遗憾的是我得到了输出:

> Doing decorator stuff!
> undefined

有人能给我指出正确的方向吗?

你得到的target将是class的原型,而不是任何实例。因此,将方法绑定到 target 将具有丢失实际实例的 this 上下文的效果,而是在原型的上下文中调用它,原型通常不会有任何这些实例属性。

您必须等到 class 方法实际被调用才能获得合适的 this。因此,忘记 target,而是在新方法中将 func 绑定到 this。并注意箭头函数不会有自己的 this 所以 descriptor.value 不应该是箭头函数(没有更多的跳箍)。所以我建议改用传统的匿名 function。因此,将 someDecorator() 的实现更改为如下所示:

function someDecorator() {
  return (target: any, _2: any, descriptor: PropertyDescriptor) => {
    const func = descriptor.value; // don't bind here
    descriptor.value = function (...args: any) {
      console.log('Doing decorator stuff!');
      func.apply(this, args); // bind here (applying args is optional I guess)
    }
  }
}

现在应该可以了:

new Foo('Hello world!').bar(); 
// Doing decorator stuff!
// Hello world!

希望对您有所帮助。祝你好运!

Link to code