使用MethodDecorator更改函数的参数,而无需更改“ this value”?

时间:2018-08-30 21:57:57

标签: javascript typescript ecmascript-6 typescript-decorator

想象一下,您必须在运行时使用装饰器更改方法参数。简单的例子:将所有参数设置为“ Hello World”:

export const SillyArguments = (): MethodDecorator => {
  return (
      target: Object,
      propertyKey: string | symbol,
      descriptor: PropertyDescriptor
  ) => {
    const originalMethod = descriptor.value;
    descriptor.value = (...args: any[]) => {
      Object.keys(args).forEach(i => {
        args[i] = 'Hello World';
      });

      return originalMethod.apply(null, args);
    };

    return descriptor;
  }
};

用法示例:

class TestClass {
  private qux = 'qux';

  @SillyArguments()
  foo(val: any) {
    console.log(val);
    console.log(this.qux);
    this.bar();
  }

  bar() {
    console.log('bar');
  }
}

const test = new TestClass();
test.foo('Ciao mondo'); // prints "Hello World"
  

TypeError:无法读取null的属性“ qux”

这里的问题是apply(null, args),它更改了this的上下文。这样就无法从qux内部调用名为foo()的实例变量。

另一种可能性是将呼叫更改为originalMethod.apply(target, args),但是这次quxundefined,而bar()可以被调用。

是否有可能将originalMethod的上下文正确设置为实例来调用this

1 个答案:

答案 0 :(得分:1)

使用function函数而不是箭头函数,以便您收到原始的this上下文并可以传递它:

export const SillyArguments = (): MethodDecorator => {
  return (
      target: Object,
      propertyKey: string | symbol,
      descriptor: PropertyDescriptor
  ) => {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      Object.keys(args).forEach(i => {
        args[i] = 'Hello World';
      });

      return originalMethod.apply(this, args);
    };

    return descriptor;
  }
};