JS装饰器 Decorator

Posted coffee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS装饰器 Decorator相关的知识,希望对你有一定的参考价值。

装饰器Decorator

参考: 阮一峰 ES6

装饰器是一种函数,写成 @函数名 它可以放在类和类方法的定义前面。与Java的注解一样,都是用于增强类的方法的。

类的装饰

@AddAge
class Person {
  
}
//这里的target就是类Person,参数只能有一个
function AddAge(target) {
  console.log(target);//[Function: Person]
  target.age=10;
}
//需要使用@ts-ignore不然无法通过预编译,即使装饰器是在编译时生效的
//@ts-ignore
console.log(Person.age);//10

装饰器就是一个对类进行处理的函数。装饰器函数的第一个参数,就是所要装饰的目标类。
如果需要添加参数,可以在外面包一层函数,如下:

@AddName(\'张三\')
class Person2{

}
function AddName(userName){
  return function(target){
    target.userName = userName;
  }
}
//@ts-ignore
console.log(Person2.userName);//张三

给类传入一个方法

function log() {
  console.log("日志输出...");
}
@addFunc([log])
class Person3 {}
function addFunc(funcs) {
  return function (target) {
    for (const func of funcs) {
      target.prototype[func.name] = func;
    }
  };
}
const p3 = new Person3();
//@ts-ignore
p3.log(); // 日志输出...

方法的装饰

class User {
  @readonly
  getName() {
    return "张三";
  }
}
/**
 *
 * @param target 类本身
 * @param name 装饰的属性(方法)名称
 * @param descriptor 属性(方法)的描述对象
 * @returns
 */
function readonly(target, name, descriptor) {
  console.log(target); //User {}
  console.log(name); //getName
  /**
   * {
   *  value: [Function: getName],
   *  writable: true,
   *  enumerable: false,
   *  configurable: true
   * }
   */
  console.log(descriptor);
  //使属性只读
  descriptor.writable = false;
  return descriptor;
}

获取类中方法名

//获取类中方法名
function GetMethodsName(target, name, descriptor) {
  if (!target.methods) {
    target.methods = [];
  }
  target.methods.push(name);
  return descriptor;
}
const u2 = new User2();
//@ts-ignore
console.log(u2.methods);//[ \'getName\', \'setName\' ]

在方法执行前后做一些操作

class User3 {
  @log
  test(args) {
    console.log("测试...",args);
  }
}
function log(target, name, descriptor) {
  const oldFunc = descriptor.value;
  descriptor.value = function () {
    console.log("方法执行前...", arguments);
    oldFunc.apply(this, arguments);
    console.log("方法执行后...", arguments);
  };
}
const u3 =new User3();
/**
 * 方法执行前... [Arguments] { \'0\': 1 }
 * 测试... 1
 * 方法执行后... [Arguments] { \'0\': 1 }
 */
u3.test(1);

注意:

  1. 对方法进行增强时记得返回方法的值!例如,上例中对方法执行前后增加日志要

     console.log("方法执行前...", arguments);
     // 最好判断一下方法是否为异步的来决定是否使用await
     const res = oldFunc.apply(this, arguments);
     console.log("方法执行后...", arguments);
     return res;
  2. 如果要获取原方法执行的结果再对结果进行处理需要判断原方法是否为异步方法,如果是异步方法需要await,判断是否为异步方法: toString.call(fn) === \'[object AsyncFunction]\';

装饰器的执行顺序

测试代码如下

@ClassDecorator
@ClassDecorator2
class A {
  @MethodDecorator
  public add(@ParamsDecorator num1: number, @ParamsDecorator num2: number) {}
}

function ClassDecorator(target: any) {
  console.log("类装饰器");
}

function ClassDecorator2(target: any) {
  console.log("类装饰器2");
}

function MethodDecorator(target: any, method: string, descriptor: any) {
  console.log("方法装饰器");
}

function ParamsDecorator(target: any, method: string, paramIndex: number) {
  console.log("参数装饰器", paramIndex);
}

输出:

参数装饰器 1
参数装饰器 0
方法装饰器
类装饰器2
类装饰器

可知:装饰器的执行顺序为,方法参数装饰器>方法装饰器>类装饰器,自右向左,自内而外。

以上是关于JS装饰器 Decorator的主要内容,如果未能解决你的问题,请参考以下文章

js装饰器@decorator学习笔记

js装饰器@decorator学习笔记

js装饰器@decorator学习笔记

python之装饰器(decorator)

Python进阶装饰器(Decorator)

python--decorator装饰器