前言
TypeScript系列文章:
- TypeScript数据类型,函数的声明和重载。
- TypeScript类和接口的使用。
本篇文章就来介绍一下TypeScript中最特殊的装饰器,装饰器对于使用JavaScript的同学肯定非常陌生,其实我对装饰器也充满了疑问,下面是我在学习TypeScript装饰器中的一些笔记和个人理解。
现在装饰器在react,vue的源码中都有应用,所以是一个非常重要的概念。
注意:本篇文章需要对JavaScript中的原型和原型链有一定的了解,因为很多概念都涉及到了原型和原型链,所以如果不清楚原型和原型链的话,可以看这篇文章:JavaScript:原型链和原型对象。
装饰器(Decorators)
什么是装饰器
- 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
- 通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
- 常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器。
- 装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)。
- Javascript里的装饰器目前处在建议征集的第二阶段,但在TypeScript里已做为一项实验性特性予以支持。
注意:装饰器是一项实验性特性,在未来的版本中可能会发生改变。
若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json
里启用experimentalDecorators
编译器选项。
命令行:
tsc --target ES5 --experimentalDecorators
tsconfig.json:
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
类装饰器
类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 类装饰器不能用在声明文件中( .d.ts
),也不能用在任何外部上下文中(比如declare
的类)。
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
function logMethos(constructor: object) {
console.log(constructor);
// params为当前类
}
@logMethos
class Student {
private name: string = "张三";
}
装饰器工厂
可以传入参数。
function logMethos(value: string) {
return function (target: any) {
target.prototype.name = value;
}
}
@logMethos("张三")
class Student {
name: string | undefined;
constructor() {
console.log("构造函数");
}
}
let s = new Student();
console.log(s.name);
这种装饰器在实际应用的过程中,使用的是非常多的,比如vue的vue-property-decorator
库中的类装饰器@Component
,可以在括号中使用js在vue中的语法。
@Component({})
export default class Home extends Vue {}
修改构造函数
function logMethos(target: any) {
return class extends target {
name:any = "李四"
}
}
@logMethos
class Student {
name: string | undefined;
constructor() {
this.name = "张三"
}
}
let s = new Student();
console.log(s.name);
属性装饰器
function logProperty(params:any) {
return function(target:any,attr:any) {
console.log(params);
console.log(target);
console.log(attr);
target[attr] = params; //修改属性
}
}
class Student{
@logProperty("张三")
name:String | undefined;
}
方法装饰器
function logMethos(params: any) {
return function (target: any, methodName: any, desc: any) {
let oMethod = desc.value;
desc.value = function (...args: any[]) {//修改修饰器方法
args = args.map((value)=> {
return String(value);
})
console.log(args);
}
}
}
class Student {
name: String | undefined;
@logMethos("张三")
getData() {
}
}
let s= new Student();
s.getData("123","211");
参数装饰器
function logParams(params: any) {
return function (target: any, paramsName: any, paramsIndex: any) {
console.log(params);
console.log(target);
console.log(paramsName);
console.log(paramsIndex);
}
}
class Student {
name: String | undefined;
getData(@logParams("213") uid:any) {
}
}
let s= new Student();
装饰器执行顺序
属性→方法→方法参数→类
为什么要用装饰器
看了上面的例子,你可能还是不知道为什么要用装饰器。
其实使用装饰器是为了使代码不具有那么强的侵入性,而且一旦装饰器使用得当,那么代码在后期维护起来会变得非常轻松。
比如下面两个例子:
最后
本来这篇文章在一个月之前就写的差不多了,但是那个时候我几乎完全不能理解为什么要使用装饰器,什么情况下使用装饰器。
在我使用了一段时间的TypeScript后,发现装饰器是一个非常棒的功能,虽然我自身用的很少,但是使用别人已经写好的装饰器,让代码显得更加的简介和明了。
我个人是非常喜欢装饰器的,而且装饰器绝对是一个值得掌握的技能,不仅使代码编写起来更加容易,同时在后期维护的时候也会更加轻松一些。
文档
装饰器