细说Typescript中的装饰器

Posted Think体验设计

tags:

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


学习Angular2的过程中,很多特性都依靠装饰器来实现,当你看到装饰器这个概念的时候,可能会把其跟设计模式里的Decorator搞混,其实这是完全不同的两个东西。


 什么是装饰器? 


虽然很像,他们要干的事都很相似——都是想要对一个已有的模块做一些“修饰工作”,所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能)侵入到原有的模块中的代码里去。但是OO的Decorator简直就是一场恶梦,不信你可以看看维基上的词条Decorator pattarn里的UML图和那些代码,不烧死一堆脑细胞才怪。


目前为止javascript中的装饰器还处于建议征集的第二阶段,在不远的ES7中大家能有幸体验一把了。Angular2最初是使用Google自己搞的AtScript语言编写的(牛逼哄哄的感觉,我要写框架了,先搞出来一种语言吧……),但是在 NG-Conf 2015 上,Angular 团队宣布与 TypeScript 团队进行合作(原因不详),但TypeScript需要引入一个类Annotation 特性的语法(及其扩展),此外为了能更好地支持 Angular,TypeScript 引入的装饰器特性并不是纯粹的装饰器提案,附加了一部分特性:


  • 支持通过 emitDecoratorMetadata 选项暴露类构造函数的参数类型;

  • 支持针对类构造器/方法参数的装饰器;

  • 支持类成员属性的装饰器。


就这样Angular与Typescript拥抱在一起了。


 装饰器的分类 


根据被装饰的对象,我们可以将TS中的装饰器分为以下四种:

  • 类装饰器 (Class decorators)

  • 属性装饰器 (Property decorators)

  • 方法装饰器 (Method decorators)

  • 参数装饰器 (Parameter decorators)


 类装饰器 


类装饰器在类声明之前被声明(紧靠着类声明)。类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(比如declare的类)。


类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。


我们来看一个例子:


可以看到,通过类装饰器我们可以对类的原型对象做一定的修改(装饰)。


编译后的源码为:

"use strict";

var __decorate = (this&&this.__decorate) ||function (decorators, target, key, desc) {

   var c =arguments.length, r = c <3? target : desc ===null? desc =Object.getOwnPropertyDescriptor(target, key) : desc, d;

   if (typeofReflect==="object"&&typeofReflect.decorate ==="function") r =Reflect.decorate(decorators, target, key, desc);

   elsefor (var i = decorators.length -1; i >=0; i--) if (d = decorators[i]) r = (c <3?d(r) : c >3?d(target, key, r) :d(target, key)) || r;

   return c >3&& r &&Object.defineProperty(target, key, r), r;

};

functionsealed(constructor) {

   Object.seal(constructor);

   Object.seal(constructor.prototype);

}

var MyClass = (function () {

   functionMyClass() {

       this.a =0;

       this.b ="hello";

   }

   MyClass =__decorate([

       sealed

   ], MyClass);

   return MyClass;

}());

var obj =newMyClass();

// obj.c = true; // 编译报错


 属性装饰器 


属性装饰器声明在一个属性声明之前(紧靠着属性声明)。属性装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如 declare的类)里。


属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:

1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

2. 成员的名字。


示例如下:

细说Typescript中的装饰器


输出如下:

细说Typescript中的装饰器


可以看到,属性装饰器返回的函数会在解释类的对应属性时被调用一次,并可以得到装饰器的参数和被装饰的属性的相关信息。


装饰器方法的调用只会在加载代码时执行一次,调用被装饰的属性不会触发装饰器方法。


 方法装饰器 


方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。方法装饰器不能用在声明文件( .d.ts),重载或者任何外部上下文(比如declare的类)中。


方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

2. 成员的名字。

3. 成员的属性描述符。


示例如下:

细说Typescript中的装饰器


输出如下:

false, undefined, [object Object], func, {"writable":true,"enumerable":true,"configurable":true}

true, this is static, functionMyClass() {

   }, sFunc, {"writable":true,"enumerable":true,"configurable":true}

call static method

call static method

call method

call method


可以看到,方法装饰器返回的函数会在解释类的对应方法时被调用一次,并可以得到装饰器的参数和被装饰的方法的相关信息。


装饰器方法的调用只会在加载代码时执行一次,调用被装饰的方法不会触发装饰器方法。


 参数装饰器 


参数装饰器声明在一个参数声明之前(紧靠着参数声明)。参数装饰器应用于类构造函数或方法声明。参数装饰器不能用在声明文件(.d.ts),重载或其它外部上下文(比如 declare的类)里。


参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:

1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。

2. 成员的名字。

3. 参数在函数参数列表中的索引。


示例如下:

细说Typescript中的装饰器


输出结果为:

1 [object Object], func, 2

2 [object Object], func, 1

3 [object Object], func, 0

4 call method

5 call method


可以看到,参数装饰器返回的函数会在解释方法的参数时被调用一次,并可以得到参数的相关信息。我们有3个参数就调用了3次。


装饰器方法的调用只会在加载代码时执行一次,调用被装饰的参数的方法不会触发装饰器方法。


 Angular中的装饰器 


理解了Typescript中的装饰器,我们回头再看Angular中的装饰器就不会感觉到鸭梨了,Angular中内置的装饰器如下:

  • 类装饰器:@Component、@NgModule、@Pipe、@Injectable

  • 属性装饰器:@Input、@Output、@ContentChild、@ContentChildren、@ViewChild、@ViewChildren

  • 方法装饰器:@HostListener

  • 参数装饰器:@Inject、@Optional、@Self、@SkipSelf、@Host

这些后续慢慢挖吧。


— END —

细说Typescript中的装饰器

    别忘了给 作者: 刘赵强 点赞呦!  

细说Typescript中的装饰器有什么想对作者说的吗?快来留言吧!细说Typescript中的装饰器

长按二维码关注“THINK”

推荐美文:



点击“阅读原文”,进入华为云官网 !

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

Typescript 中的装饰器返回函数的时间

TypeScript 素描 - 装饰器

关于何时在 TypeScript 中调用装饰器的困惑

使用Typescript和类组件装饰器时如何将数组传递给Vue中的props

typescript 如何通过TypeScript中的装饰器更改实例属性:http://romkevandermeulen.nl/2018/01/24/typescript-property-deco

C#中的 Attribute 与 Python/TypeScript 中的装饰器是同个东西吗