Decorators TypeScript 装饰器

Decorators

装饰器(Decorator)用来增强 JavaScript 类(class)的功能,许多面向对象的语言都有这种语法,目前有一个提案将其引入了 ECMAScript。
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上。 装饰器使用@expression 这种形式,expression 求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。

A First Class Decorator

类装饰器是我们最常使用到的,它的通常作用是,为该类扩展功能。

function Logger(constructor: Function) {
   
  console.log("Logging...");
  console.log(constructor);
}

@Logger
class Person {
   
  name = "Jack";
  constructor() {
   
    console.log("Creating person object....");
  }
}

const person = new Person();

console.log(person);

在这里,Logger 就是一个装饰器。使用的时候,在类声明前一行使用 @ 后跟装饰器名字使用。这里用作类装饰器。
类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。
类装饰器表达式会在运行时当做函数被调用,类的构造函数函数作为其唯一的参数。
现在运行这段代码,看看会有什么。

Logging...
class Person {
    construcotr() {
        this.name = "Jack";
        console.log("Creating person object....")
    }
}
Creating person object....
Person { name: 'Jack' }

首先可以看的到,装饰器内的输出先于我们实例化 Person 的输出。装饰器在类被定义的时候执行,而不是实例化的时候,事实上不需要做实例化也会执行。

Why Decorator?

设想有这样一个场景。
目前有一个 Tank 类,有一个 Plane 类,有一个 Animal 类。这三个类都需要一个公共的方法来获取他们所在的位置。我们第一可能想到使用继承来实现。

class BaseClass {
   
  getPosition() {
   
    return {
   
      x: 100,
      y: 200,
      z: 300,
    };
  }
}
class Tank extends BaseClass {
   }
class Plane extends BaseClass {
   }
class Animal extends BaseClass {
   }

这样三个类都可以调用 getPosition 方法来获取各自的位置了。到目前为止看起来没什么问题。

现在又有了一个新的诉求,Tank 类和Plane类需要一个新的方法addPetrol来给坦克和飞机加油。而动物不需要加油。此时这种写法好像不能继续进行下去了。而 js 目前没有直接语法提供多继承的功能,我们的继承方式好像行不通了。这时候装饰器可以很完美的实现这样的功能。此时就可以请我们的装饰器闪亮登场了

装饰器功能之——能力扩展
我们把getPositionaddPertrol都抽象成一个单独的功能,它们得作用是给宿主扩展对应的功能。

const getPositionDecorator: ClassDecorator = (constructor: Function) => {
   
  constructor.prototype.getPosition = () => {
   
    return [100, 200];
  };
};

const addPetrolDecorator: ClassDecorator = (constructor: Function) => {
   
  constructor.prototype.addPetrol = () => {
   
    // do something
    console.log(`${
     constructor.name}进行加油`);
  };
};

@addPetrolDecorator
@getPositionDecorator
class Tank {
   }
@addPetrolDecorator
@getPositionDecorator
class Plane {
   }

@getPositionDecorator
class Animal {
   }

这样的话,加入日后我们有其他的猫猫狗狗,都可以对他进行能力扩展,让其具有加油的能力。

多个装饰器叠加的时候,执行顺序为离被装饰对象越近的装饰器越先执行。下面有更详细的章节。

Working with a Decorator Factories

可以通过装饰器工厂创建装饰器

function Logger(logString: string) {
   
  return function (constructor: Function) {
   
    console.log(logString);
    console.log(constructor);
  };
}

@Logger("LOGGING - PERSON")
class Person2 {
   
  name = "Jack";
  constructor() {
   
    console.log("Creating person object....");
  }
}

在这里面我们返回一个函数,同时,我们有能力接受参数了,这让我们可以对装饰器有更高的灵活性,更多的可能性。实用性会更强。

Building More Useful Decorator

来看看装饰器还能干嘛

function WithTemplate(template: string, hookId: string) {
   
  return function (constructor: any) {
   
    const hookEl = document.getElementById(hookId);
    const p = new constructor();
    if (hookEl) {
   
      hookEl.innerHTML = template;
      hookEl.querySelector("h1")!.textContent = p.name;
    }
  };
}

@WithTemplate("<h1></h1>", "app")
class P {
   
  namme = "Jack";
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值