6-1 类的装饰器(1)

“dev”: “ts-node ./src/index.ts”
装饰器, 本身是一个函数,
使用?通过@符号来使用
参数?构造函数
执行顺序?先近后远
添加配置

  1. "experimentalDecorators": true,
  2. "emitDecoratorMetadata": true

index.ts

  1. function testDecorator(constructor: any) {
  2. constructor.prototype.getName = () => {
  3. console.log('hello')
  4. }
  5. // console.log('Decorator')
  6. }
  7. @testDecorator
  8. class Test {}
  9. const test = new Test()
  10. // 方式二, 函数装饰器作为返回函数, 且装饰器可以传递参数
  11. function testDecorator() {
  12. return function(constructor: any) {
  13. constructor.prototype.getName = () => {
  14. console.log('hello')
  15. }
  16. }
  17. }
  18. @testDecorator()
  19. class Test {}

6-2 类的装饰器(2)

构造函数new (…args: any[]) => any

  1. function testDecorator<T extends new (...args: any[]) => any>(constructor: T) {
  2. return class extends constructor {
  3. name = 'Lcuy'
  4. getName() {
  5. return this.name;
  6. }
  7. };
  8. }
  9. @testDecorator
  10. class Test {
  11. name: string;
  12. constructor(name: string) {
  13. this.name = name
  14. }
  15. }
  16. const test = new Test('Jack')
  17. console.log(test.getName())

执行顺序?

修正错误提示

  1. function testDecorator() {
  2. return function<T extends new (...args: any[]) => any>(constructor: T) {
  3. return class extends constructor {
  4. name = 'Lcuy'
  5. getName() {
  6. return this.name;
  7. }
  8. };
  9. }
  10. }
  11. const Test = testDecorator() {
  12. class {
  13. name: string;
  14. constructor(name: string) {
  15. this.name = name
  16. }
  17. }
  18. }
  19. const test = new Test('Jack')
  20. console.log(test.getName())

6-3 方法装饰器

  1. // 普通方法,target 对应类的prototype, key需要装饰的方法的名字
  2. // 静态方法, target 对应的是类的构造函数,
  3. function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
  4. descriptor.writable = false
  5. descriptor.value = function() {
  6. return 'Decorator '
  7. }
  8. }
  9. class Test {
  10. name: string;
  11. constructor(name: string) {
  12. this.name = name
  13. }
  14. @getNameDecorator
  15. getName() {
  16. return this.name;
  17. }
  18. }
  19. const test = new Test('Jack')
  20. // 若修改方法
  21. test.getName = () => {
  22. return "abc"
  23. }
  24. console.log(test.getName())

6-4 访问器的装饰器

访问器? get/set 访问器, 但是不能同时使用装饰器

  1. function visitDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
  2. // descriptor.writable = false
  3. }
  4. class Test {
  5. private _name: string;
  6. constructor(name: string) {
  7. this._name = name
  8. }
  9. get name() {
  10. return this._name
  11. }
  12. @visitDecorator
  13. set name(name: string) {
  14. this._name = name
  15. }
  16. }
  17. const test = new Test('Jack')
  18. // set
  19. test.name = '123'
  20. // get
  21. console.log(test.getName()) // 123

6-5 属性的装饰器

参数有所不同(无法接受descriptor)

  1. function nameDecorator(target: any, key: string): any {
  2. // target[key] = 'Lee' // 修改的prototye
  3. const descriptor: PropertyDescriptor = {
  4. writable: false
  5. }
  6. return descriptor;
  7. }
  8. class Test {
  9. @nameDecorator
  10. name = "Jack"
  11. }
  12. const test = new Test()
  13. test.name = '123'
  14. console.log(test.getName()) // 123

6-6 参数装饰器

  1. // 原型, 方法, 参数所在的位置
  2. function paramDecorator(target: any, key: string, paramIndex: number) {
  3. }
  4. class Test {
  5. getInfo(@paramDecorator name: string, age: number) {
  6. }
  7. }
  8. const test = new Test()
  9. test.getInfo("Jack", 28)

6-7 装饰器应用

需求: 错误捕获封装到装饰器中

  1. const userInfo: any = undefined;
  2. function catchError(msg: string) {
  3. return function(target: any, key: string, descriptor: PropertyDescriptor) {
  4. const fn = descriptor.value
  5. // 重写函数内容
  6. descriptor.value = function() {
  7. try {
  8. fn();
  9. } catch (e) {
  10. console.error(msg)
  11. }
  12. }
  13. }
  14. }
  15. class Test {
  16. @catchError("name undefined")
  17. getName() {
  18. return userInfo.name;
  19. }
  20. @catchError("age undefined")
  21. getAge() {
  22. return userInfo.age;
  23. }
  24. }

6-8 reflect-metadata

yarn add reflect-metadata
应用1, 定义原(?)数据

  1. import 'reflect-metadata'
  2. const user = {
  3. name: 'Jack'
  4. }
  5. Reflect.defineMetadata('age', 28, user)
  6. console.log(Reflect.getMetadata('age', user))

应用2, 原数据定义到类上

  1. import 'reflect-metadata'
  2. @Reflect.metadata('age', 16)
  3. class User = {
  4. name: 'Jack'
  5. }
  6. console.log(Reflect.getMetadata('age', User))

应用, 原数据定义到属性上

  1. import 'reflect-metadata'
  2. class User = {
  3. @Reflect.metadata('age', 16)
  4. name: 'Jack'
  5. }
  6. console.log(Reflect.getMetadata('age', User.prototype, 'age'))

应用, 原数据定义到方法上

  1. import 'reflect-metadata'
  2. class User {
  3. @Reflect.metadata('age', 16)
  4. getName() {}
  5. }
  6. console.log(Reflect.getMetadata('age', User.prototype, 'getName'))

常见方法

  • metadata
  • defineMetadata
  • hasMetadata
  • hasOwnMetadata, 区别在于是否来自于继承
  • hasMetadataKeys(‘age’, User.prototype, ‘age’), 获取原数据的key
  • hasOwnMetadataKeys

6-9 装饰器的执行顺序

方法装饰器优先于类装饰器执行

  1. import 'reflect-metadata'
  2. function showData(target: typeof User) {
  3. for (let key in target.prototype) {
  4. const data = Reflect.getMetadata('data', target.prototype, key)
  5. console.log(data)
  6. }
  7. }
  8. @showData
  9. class User {
  10. @Reflect.metadata('data', 'name')
  11. getName() {}
  12. @Reflect.metadata('data', 'age')
  13. getAge() {}
  14. }
  15. // name
  16. // age

创建自己的装饰器

  1. import 'reflect-metadata'
  2. function showData(target: typeof User) {
  3. for (let key in target.prototype) {
  4. const data = Reflect.getMetadata('data', target.prototype, key)
  5. console.log(data)
  6. }
  7. }
  8. function setData(dataKey: string, mag: string) {
  9. return function(target: User, key: string) {
  10. Reflect.defineMetadata(dataKey, msg, target, key)
  11. }
  12. }
  13. @showData
  14. class User {
  15. // @Reflect.metadata('data', 'name')
  16. @setData('data', 'name')
  17. getName() {}
  18. @setData('data', 'age')
  19. getAge() {}
  20. }
  21. // name
  22. // age

END 202-5-5