装饰器(Decorator)

103 阅读2分钟

概述

装饰器(Decorator)用来增强 JavaScript 类(class)的功能,装饰器是一种在代码运行时动态添加功能的方式,它通常用于修改类或函数的行为.

ts中启用装饰器需要experimentalDecorators 设置为ture.

装饰器使用 @expression 的形式,其中 expression 必须是一个可以返回函数的expression ,该函数在运行时会被调用,并传递有关被装饰声明的信息。

装饰器本质上是一个函数,用于修改类或类成员的行为。装饰器可以应用于类、类的方法、访问器、属性和参数。

普通装饰器,代码如下:

function color(target: Function) {
    target.prototype.color = 'red';
 }
 
@color
class D {
  color: string;
}
const d = new D();
console.log(d.color)

装饰器工厂的形式可以增加参数,代码更加灵活:

function color(col:string) {
  // 这是装饰器工厂,设置了返回的装饰器函数
  return function (target: Function) {
    console.log('factory called')
    target.prototype.color = col;
  }
}
@color('reds')
class D {
  color: string;
}
const d = new D();
console.log(d.color)

装饰器的类型

  1. 类装饰器:用于修饰整个类。
  2. 方法装饰器:用于修饰类的方法。
  3. 访问器装饰器:用于修饰类的 getter 或 setter 方法。
  4. 属性装饰器:用于修饰类的属性。
  5. 参数装饰器:用于修饰方法的参数。

示例

类装饰器

类装饰器接收一个参数,即被装饰的类。

function classDecorator(target) {
  target.prototype.decorated = true;
}

@classDecorator
class MyClass {}

const obj = new MyClass();
console.log(obj.decorated); // true

方法装饰器

方法装饰器接收三个参数:目标对象、方法名和属性描述符。

对于原型上的方法:target指的是类的原型,静态方法target指的是类。

function methodsDecorator(target, key, descriptor) {
  console.log('methodsDecorator', target === D.prototype, key, descriptor)
}

class D {
  @methodsDecorator
  change(){
	  
  }
}

实现一个执行方法时打印日志的装饰器

function log(target, key, descriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args) {
    console.log(`Calling ${key} with arguments:`, args);
    const result = originalMethod.apply(this, args);
    console.log(`Result:`, result);
    return result;
  };

  return descriptor;
}

class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}

const calc = new Calculator();
calc.add(2, 3);
// Output:
// Calling add with arguments: [2, 3]
// Result: 5

访问器装饰器

访问器装饰器接收三个参数:目标对象、属性名和属性描述符。

对于原型上的方法:target指的是类的原型,静态方法target指的是类。

function accessorDecorator(target, key, descriptor) {
  const originalGet = descriptor.get;

  descriptor.get = function() {
    console.log(`Getting value of ${key}`);
    return originalGet.call(this);
  };

  return descriptor;
}

class MyClass {
  constructor(value) {
    this._value = value;
  }

  @accessorDecorator
  get value() {
    return this._value;
  }
}

const obj = new MyClass(42);
console.log(obj.value);
// Output:
// Getting value of value
// 42

属性装饰器

属性装饰器接收两个参数:目标对象和属性名。

对于原型上的属性:target指的是类的原型,静态属性target指的是类。

function propertyDecorator(target, key) {
  let value = target[key];

  const getter = () => {
    console.log(`Getting value of ${key}`);
    return value;
  };

  const setter = newValue => {
    console.log(`Setting value of ${key} to ${newValue}`);
    value = newValue;
  };

  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true
  });
}

class MyClass {
  @propertyDecorator
  myProperty;
}

const obj = new MyClass();
obj.myProperty = 123;
// Output: Setting value of myProperty to 123
console.log(obj.myProperty);
// Output: Getting value of myProperty
// 123

参数装饰器

参数装饰器接收三个参数:目标对象、方法名和参数索引。

对于原型上的方法:target指的是类的原型,静态方法target指的是类。

function parameterDecorator(target, key, index) {
  const metadataKey = `__${key}_parameters`;
  if (Array.isArray(target[metadataKey])) {
    target[metadataKey].push(index);
  } else {
    target[metadataKey] = [index];
  }
}

class MyClass {
  myMethod(@parameterDecorator param1, param2) {
    console.log(param1, param2);
  }
}

const obj = new MyClass();
obj.myMethod('a', 'b');
// Output: a b