# 1. 装饰器

装饰器函数(Decorator)用于给对象在运行期间动态的增加某个功能,职责等,装饰器本身是一个函数。

# 1.1. 类装饰器

类装饰器接受的参数是构造函数。通过下面的方法可以让装饰后的类获取到装饰器中定义的方法,否则无此方法提示。

function testDecorator() {
  return function <T extends new (...args: any[]) => any>(constructor: T) {
    return class extends constructor {
      name = "xiansheng";
      getName() {
        return this.name;
      }
    };
  };
}

const Test = testDecorator()(
  class {
    name: string;
    constructor(name: string) {
      this.name = name;
    }
  }
);

const test = new Test("haha");
console.log(test.getName());

# 1.2. 类中方法的装饰器

  • 普通方法,target 对应的是类的 prototype
  • 静态方法,target 对应的是类的构造函数
function getNameDecorator(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {
  // console.log(target, key);
  // descriptor.writable = true;
  descriptor.value = function () {
    return "decorator";
  };
}

class Test {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
  @getNameDecorator
  getName() {
    return this.name;
  }
}

const test = new Test("haha");
console.log(test.getName());
// -> decorator

# 1.3. 类的访问器装饰器

function visitDecorator(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {
  descriptor.writable = false;
}

class Test {
  private _name: string;
  constructor(name: string) {
    this._name = name;
  }
  get name() {
    return this._name;
  }
  @visitDecorator
  set name(name: string) {
    this._name = name;
  }
}

const test = new Test("hu");
test.name = "yao"; // 报错
console.log(test.name);

# 1.4. 属性的装饰器

  • 可返回 descriptor
  • target 上修改的是原型上属性
function nameDecorator1(target: any, key: string): any {
  const descriptor: PropertyDescriptor = {
    writable: false,
  };
  return descriptor;
}

// 修改的并不是实例上的 name, 而是原型上的 name
function nameDecorator2(target: any, key: string): any {
  target[key] = 20;
}

// name 放在实例上
class Test {
  @nameDecorator1
  name = "a";
  @nameDecorator2
  age = 18;
}

const test = new Test();
console.log((test as any).__proto__.name);

# 1.5. 参数装饰器

// 原型,方法名,参数所在的位置
function paramDecorator(target: any, method: string, paramIndex: number) {
  console.log(target, method, paramIndex);
}

class Test {
  getInfo(name: string, @paramDecorator age: number) {
    console.log(name, age);
  }
}

const test = new Test();
test.getInfo("a", 20);