细说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. 成员的名字。
示例如下:
输出如下:
可以看到,属性装饰器返回的函数会在解释类的对应属性时被调用一次,并可以得到装饰器的参数和被装饰的属性的相关信息。
装饰器方法的调用只会在加载代码时执行一次,调用被装饰的属性不会触发装饰器方法。
方法装饰器
方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。它会被应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义。方法装饰器不能用在声明文件( .d.ts),重载或者任何外部上下文(比如declare的类)中。
方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2. 成员的名字。
3. 成员的属性描述符。
示例如下:
输出如下:
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. 参数在函数参数列表中的索引。
示例如下:
输出结果为:
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 —
别忘了给 作者: 刘赵强 点赞呦!
有什么想对作者说的吗?快来留言吧!
长按二维码关注“THINK”
推荐美文:
点击“阅读原文”,进入华为云官网 !
以上是关于细说Typescript中的装饰器的主要内容,如果未能解决你的问题,请参考以下文章
使用Typescript和类组件装饰器时如何将数组传递给Vue中的props
typescript 如何通过TypeScript中的装饰器更改实例属性:http://romkevandermeulen.nl/2018/01/24/typescript-property-deco