简介

JS 装饰器(Decorator) Decorator 是ES7 的一个新语法,目前仍处于第2阶段提案中。
装饰器可以修饰类、类的属性、类的原型上的方法,修饰的时候 就是把这个类,属性、方法 … 传递给修饰的函数。

环境配置

浏览器无法识别 decorator 语法,需要用 babel 转化为 ES5 语法。

安装Babel

  1. npm install @babel/cli @babel/core @babel/preset-env

@babel/core 包含了 Babel的核心功能。
@babel/cli 是一个能从终端(命令行)使用的工具。
@babel/preset-env 可以智能的判断语言的版本并把它转化成 ES5 语法

安装 decorator 插件

  1. npm install --save-dev @babel/plugin-proposal-decorators

配置文件

在运行目录下添加一个 .babelrc 文件,配置预设包 和 插件,如下:

  1. {
  2. "presets": [
  3. "@babel/preset-env"
  4. ],
  5. "plugins": [
  6. [
  7. "@babel/plugin-proposal-decorators",
  8. {
  9. "legacy": true
  10. }
  11. ],
  12. [
  13. "@babel/plugin-proposal-class-properties"
  14. ]
  15. ]
  16. }

2022更新 @babel/plugin-proposal-class-properties 已经被包裹在@babel/preset-env 中,不需要额外配置。

运行

  1. npx babel 2.class.decorator.js -o es5.js -w
  2. //得到结果,在同目录下生成一个 es5.js 文件,同时 -w 监听这个文件变动

生成之后就可以直接运行这个es5.js文件了。

语法

作用于类的装饰器

简单的类装饰器

类的装饰器函数的第一个参数,就是所有装饰的目标类,如下:

  1. @flag
  2. class Animal {}
  3. //装饰器函数
  4. function flag(target) {
  5. target.type = '哺乳类'
  6. }
  7. console.log(Animal.type);//哺乳类

给类装饰器传参数

  1. @flag('装饰器参数')
  2. class Animal {}
  3. //装饰器函数
  4. function flag(param) {
  5. console.log(param);//装饰器参数
  6. return function(constructor){
  7. constructor.type = '哺乳类'
  8. }
  9. }
  10. console.log(Animal.type);//哺乳类

作用于方法的类装饰器

方法的装饰器函数拥有三个参数:

  • target 构造函数的原型对象
  • property 属性名
  • descriptor 属性名描述符 value、enumerable、configurable、writable,没有get、set ```javascript class Animal { PI = 3.14; name = ‘xxx’; //实例上的属性 并不是原型上的属性 @before say(a, b, c) {
    1. console.log('说话', a, b, c, this.a)
    } a() {
    1. return 1;
    } }

let animal = new Animal();

//利用装饰器函数创建一个aop函数(面向切片编程)。 function before(target, property, descriptor) { //因为执行before时,构造函数尚未创建完成,所以这边异步获取。 setTimeout(()=>{ console.log(target === Animal.prototype);//true console.log(property);//say console.log(descriptor);//{value: [Function: say],writable: true,enumerable: false,configurable: true} },100)

  1. //函数装饰器(保留原有功能不变,添加新的逻辑)
  2. let oldSay = descriptor.value;
  3. descriptor.value = function (...args) {
  4. console.log('before');
  5. oldSay(...args);
  6. console.log('after');
  7. }

} animal.say(1, 2, 3);

  1. <a name="aLZ83"></a>
  2. ### 作用于属性的类装饰器(ES7)
  3. 在 ES6 中,装饰器不支持装饰属性,在ES7中才添加进来。<br />同样拥有三个参数:
  4. - target 构造函数的原型对象
  5. - property 属性名
  6. - descriptor 属性名描述符 value、enumerable、configurable、writable,没有get、set。
  7. ```javascript
  8. class Animal {
  9. @readonly
  10. PI = 3.14;
  11. name = 'xxx'; //实例上的属性 并不是原型上的属性
  12. say(a, b, c) {
  13. console.log('说话', a, b, c, this.a)
  14. }
  15. a() {
  16. return 1;
  17. }
  18. }
  19. function readonly(target, property, descriptor) {
  20. descriptor.writable = false;
  21. // setTimeout(() => {
  22. // console.log(target === Animal.prototype);
  23. // console.log(arguments)
  24. // })
  25. }
  26. let animal = new Animal();
  27. animal.PI = 3.15;//TypeError: Cannot assign to read only property 'PI' of object '#<Animal>'