带有第二阶段提案和Babel 7的类装饰器

时间:2019-03-22 21:04:44

标签: javascript class decorator babel ecmascript-next

我正在研究阶段2装饰器的建议,但发现类装饰器存在一些问题。在旧版装饰器中,下一个示例可行,因为类装饰器将目标构造函数作为唯一参数,但是在阶段2提议中,它接收到对象描述符。

function log(Class) {
  return (...args) => {
    console.log(`Arguments: ${args}`);

    return new Class(...args);
  };
}

@log
class Bar {
  constructor(name, age) { }
}

我已经阅读了tc39提案装饰器和内置装饰器,但是并没有太大帮助。如何使该示例与新的投标装饰器一起使用?可以将内置装饰器与babel一起使用吗?

为了尝试一些东西,我开发了自己的基本包装装饰器,它可以按预期的方法使用,并且我想将其功能扩展到类。

const wrap = f => {
 return wrapped => {
   const { kind } = wrapped;

   if (kind === 'class') {
     return f(wrapped);
   }
   const { descriptor } = wrapped;
   const original = descriptor.value;

   descriptor.value = f(original);

   return { ...wrapped, descriptor };
  };
};

export default wrap;

有了这个基本的装饰器,我就可以创建可以正常工作的logger方法装饰器。

import wrap from './wrap';

const loggerFunction = f => {
  const name = f.name;

  return function test(...args) {
    console.log(`starting ${name} with arguments ${args.join(', ')}`);

    return f.call(this, ...args);
  };
};

export default wrap(loggerFunction);

我可以通过这种方式使用它:

class Foo {
  @logger
  method(argument) {
    return argument;
  }
}

1 个答案:

答案 0 :(得分:1)

您的问题有点老了,但我认为它仍然是实际的,所以这是我的答案:

TLDR:在使用非旧版阶段2装饰器时,请使用finisher属性包装您的类。

第2阶段的API尚未完全记录,缺少某些内容和用例。

为了实现所需的功能,请在装饰器中返回的对象上定义特殊的finisher属性。

因此,此legacy阶段1装饰代码:

function log(Class) {
  return (...args) => {
    console.log(`Arguments: ${args}`);

    return new Class(...args);
  };
}

@log
class Bar {
  constructor(name, age) { }
}

等同于此non-legacy第二阶段装饰器代码:

function log(descriptor) {
  return {
    ...descriptor,
    finisher: (Class) => (...args) => {
      console.log(`Arguments: ${args}`);

      return new Class(...args);
    },
  };
}

@log
class Bar {
  constructor(name, age) {}
}

您可以将相同的原理应用于wrap函数。