案例
@frozen class Foo {
@configurable(false) // 可配置的
@enumberable(true) // 可枚举的
method () {}
@throttle(500) // 节流
expensiveMethod () {}
}
上面代码一共使用了四个装饰器
- 一个用在类本身(@frozen)
- 另外三个用在类方法(@configurable()、@enumberable()、@throttle())
不仅增加了代码的可读性,清晰地表达了意图
而且提供一种方便的手段,增加或修改类的功能
装饰器API类型
type Decorator = (
value: Input,
context: {
// 装饰类型: 字符串 (可能的取值有: class、method、getter、setter、field、accessor)
kind: string;
// 被装饰的值的名称
name: string | symbol;
// 对象: 存值器和取值器
access: {
get?(): unknown;
set?(value: unknown): void
};
// 私有元素: 布尔值
private?: boolean;
// 静态元素: 布尔值
static?: boolean;
// 函数,允许用户增加初始值逻辑
addInitializer?(initializer: () => void): void
}
) => Output | void
装饰器函数,两参数。
- value: 被装饰的值,某些情况下可能是
undefined(装饰属性时) - context: 上下文信息对象
装饰器函数的返回值,是一个新版本的装饰对象,但也可以不返回任何值(void)
1、装饰器和继承的区别
2、配置typescript装饰器环境
3、typescript类装饰decorator器使用基础
const moveDecorator = (target) => {
}
@moveDecorator
class Tank {}
@moveDecorator
class Player {}
class Tank {} 是装饰器 moveDecorator 的 参数,也就是target是class Tank这个类
class Player {} 也是如此
获取位置
const moveDecorator = (target: Function) => {
target.prototype.getPosition = (): { x: number, y: number } => {
return { x: 100, y: 200 }
}
}
@moveDecorator
class Tank {
public getPosition() {} // 这个是为了下面typescript中t找不到getPosition的报错加的, 也可以去掉加断言
}
const t = new Tank()
console.log(t.getPosition()) // { x: 100, y: 200 }
也可以去掉,加断言
const moveDecorator = (target: Function) => {
target.prototype.getPosition = (): { x: number, y: number } => {
return { x: 100, y: 200 }
}
}
@moveDecorator
class Tank {
}
const t = new Tank()
console.log((t as any).getPosition()) // { x: 100, y: 200 }
// 也可以 console.log((<any>t).getPosition()) // { x: 100, y: 200 }
语法糖
@decoratorName 这种就是语法糖的形式。装饰器归根结底还是跟原型链脱不了干系。
所以如果是类的装饰器,就是把类的构造函数传到函数里面作为参数,只不过我们使用这种@decoratorName语法糖这种形式会自动帮我们操作,不需要我们人为的调用。
执行步骤
装饰器的执行步骤如下。
- 计算各个装饰器的值,按照从左到右,从上到下的顺序。
- 调用方法装饰器。
- 调用类装饰器。
特点
使用装饰器来包装代码,语法更加简单优雅,编写的代码可读性更高也更易于理解。
装饰器其实本质上来讲就是一个函数。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天 点击查看活动详情