如何使用和应用 JavaScript 装饰器?

How do I use and apply JavaScript decorators?

我试图了解如何在一段非常简单的代码中使用装饰器,这样我就可以将这个概念应用到我更大的项目中。借鉴 Addy Osmani 的文章 here,我创建了一段简单的代码,如下所示。

说,我有一个名为 Cat 的 class,有一个 meow() 方法,我想用一些日志记录来装饰它,如下所示。

class Cat {
  @logger
  meow() { console.log( ' Meeeoow! ') }
};


function logger(target, key, descriptor) {
  console.log("Cat snarling...");
  return descriptor;
}

const cat = new Cat();
cat.meow();

当我尝试针对 Node.js 解释器(版本 9.1.0)执行此操作时,出现以下错误。

/Users/ravindranath/projects/decorators/index.js:2   @logger   ^

SyntaxError: Invalid or unexpected token
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:152:10)
    at Module._compile (module.js:605:28)
    at Object.Module._extensions..js (module.js:652:10)
    at Module.load (module.js:560:32)
    at tryModuleLoad (module.js:503:12)
    at Function.Module._load (module.js:495:3)
    at Function.Module.runMain (module.js:682:10)
    at startup (bootstrap_node.js:191:16)
    at bootstrap_node.js:613:3

所以,我的问题是:

  1. Node.js9.x是否支持装饰器语法?或者它会在未来的某个版本中出现吗?

  2. 我在 GitHub 上看到一些基于 express-js 的装饰器,但我不知道如何创建自己的装饰器。有人可以提供一个使用 Node.js?

  3. 创建自定义装饰器的简单基本示例

装饰器不是 ECMAScript 2016(又名 7)的一部分。装饰器目前在 Stage 2 Draft out of the total 4 stages a feature goes through before being finalized and becoming part of the language. They'll probably be integrated into the language in the near future, but its features and specifics are subject to change. Because of this, you'll have to use a transpiler such as Babel to transform the decorators into code the Node runtime can understand (ECMAScript 2016) by installing the transform-decorators Babel 插件中。

至于创建装饰器,您已经这样做了。每个装饰器只是一个包装另一个装饰器的函数,根据用例提供参数,在您的情况下为 targetkeydescriptor。您的 logger 函数:

function logger(target, key, descriptor) {
  console.log("Cat snarling...");
  return descriptor;
}

已经是装饰师了。对于class属性和方法target指的是属性的class,key就是属性 名称,而 descriptor 是 属性 的描述符。然后调用装饰器,class 的 属性 在脱糖后通过 Object.defineProperty 定义。您的示例可以归结为:

class Cat { }

let meowDescriptor = {
  type: 'method',
  initializer: () => () => {
    console.log(' Meeeoow! ');
  },
  enumerable: false,
  configurable: true,
  writable: true
}

function logger(target, key, descriptor) {
  console.log("Cat snarling...");
  return descriptor;
}

meowDescriptor = logger(Cat.prototype, 'meow', meowDescriptor);
Object.defineProperty(Cat.prototype, 'meow', {
  ...meowDescriptor,
  value: meowDescriptor.initializer()
});

对于 classes 本身,装饰器接受一个参数,target,它描述了被装饰的 class。我建议阅读有关该主题的 some documentation 以熟悉它。