装饰器语法

72 阅读1分钟

使用

(1) 装饰器还在 proposal 阶段,在 react 项目中使用需要装一些依赖支持:

yarn add @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties

(2) package.json 文件中添加配置:

 "plugins": [
      [
        "@babel/plugin-proposal-decorators",
        {
          "legacy": true
        }
      ],
      [
        "@babel/plugin-proposal-class-properties",
        {
          "loose": true
        }
      ]
    ]

image.png

类的装饰器

(1)语法:

const test = (target) => {
  target.name1 = 'name';
  target.fn = () => {};
};
// 修饰类的装饰器:相当于test(Demo)
@test
class Demo {}
console.dir(Demo);

(2)console.dir(Demo) 输出:

截屏2023-03-26 10.51.18.png

类的属性装饰器

(1) 语法:

const test = (target, name, descriptor) => {
  /* 
  target:Demo.prototype
  name:'x'
  descriptor:{configurable: true, enumerable: true, writable: true, initializer: ƒ}  修饰的属性,则初始值是基于initializer函数设置的!! 
  */
  /* 
  target:Demo.prototype
  name:'getX'
  descriptor:{configurable: true, enumerable: false, writable: true, value: ƒ}  修饰的函数,则初始值是基于value属性设置的!! 
  */
  console.log(target, name, descriptor);
};
class Demo {
  @test x;
  @test
  getX() {}
}
// 给类的属性设置装饰器,创建实例触发装饰器执行
let d = new Demo();
console.log(d);

(2) console.log(target, name, descriptor); 输出结果

截屏2023-03-26 11.01.19.png

装饰器实例

const readonly = (_target, _name, descriptor) => {
  // 设置为不可修改
  descriptor.writable = false;
};
// 记录函数运行所需时间
const logTimer = (_target, name, descriptor) => {
  // 原来的函数
  const originFn = descriptor.value;
  descriptor.value = function (...params) {
    console.time(name);
    const res = originFn.apply(this, ...params);
    console.timeEnd(name);
    return res;
  };
};
class DemoDecorator {
  @readonly x = 100;
  @logTimer
  getX() {
    for (let i = 0; i < 100000000; i++) {}
    return this.x;
  }
}
const demo = new DemoDecorator();
console.log(demo.getX());

输出结果:

截屏2023-03-26 11.13.33.png

总结

类和属性都可以有多个装饰器,从下到上处理;同一个装饰器也可以作用于多个对象。