感兴趣的欢迎关注公众号“胖蔡话前端”,了解更多前端面试题。可扫描右侧二维码关注。
ts装饰器是什么
装饰器是通过添加标注的方式,来对类型进行扩展的一种方式。
- 只能在类中使用
- 减少冗余代码量
- 提高代码扩展性
ts装饰器的语法
装饰器的使用非常简单,装饰器本质就是一个函数,在特定的位置调用装饰器函数即可对数据(类、方法、甚至参数等)进行扩展。下面例子演示给 MyTestableClass 类添加静态属性 isTestable:
@testable
class MyTestableClass {}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
装饰器的分类
装饰器 是一个函数,它可以通过 @funName 在类、方法、访问符、属性、参数上,对它们进行包装,然后返回一个包装后的目标对象(类、方法 、访问符、属性、参数)
- 类装饰器类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。下面例子演示给 MyTestableClass 类添加静态属性 isTestable:
@testable class MyTestableClass {} function testable(target) { target.isTestable = true; } MyTestableClass.isTestable // true
- 类方法装饰器方法装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 成员的名字。 成员的属性描述符。
下面的例子演示让类的方法变为只读。
(1)实例方法
function readonly(target, name, descriptor) { descriptor.writable = false; return descriptor; } class Cat { @readonly say() { console.log("meow ~"); } }
(2)静态方法
class MyTestableClass { @testable static sleep() {} } function testable(target, name, descriptor) { target.isTestable = true; } MyTestableClass.isTestable // true
- 类属性装饰器属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 成员的名字。 属性描述符不会做为参数传入属性装饰器,这与TypeScript是如何初始化属性装饰器的有关。官方文档有说明。
class MyTestableClass { @testable name: string; constructor(name: string) { this.name = name; } } function testable(target, name) { console.log(arguments) }
- 参数装饰器参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数: 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 成员的名字。 参数在函数参数列表中的索引。 注意 参数装饰器只能用来监视一个方法的参数是否被传入。参数装饰器的返回值会被忽略。
class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet(@required name: string) { return "Hello " + name + ", " + this.greeting; } }
装饰器的执行顺序
实例装饰器:属性装饰 -> 访问器装饰 -> 参数装饰 => 方法装饰 静态装饰器: 属性 => 访问器 => 参数 => 方法 类装饰器
复合装饰器
@d1
@d2
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function d1(target: Function) {}
function d2(target: Function) {}
装饰器工厂
如果我们需要给装饰器执行过程中传入一些参数的时候,就可以使用装饰器工厂来实现,它返回一个装饰器函数。
@Controller('user')
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
function Controller(path: string) {
return function (target: Function) {
(target as any).path = path;
}
}