我正在参加「掘金·启航计划」
1. 概念
- 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上;
- 装饰器使用@expression这种形式,expression求值后必须为一个函数,它会在运行时被调用;
- 装饰器本质上就是一个函数;
- 装饰器是一项实验性特性,在未来的版本中可能会发生改变;
2. 不同的装饰器
2.1 类的装饰器
类装饰器声明在类声明之前。类装饰器应用于类的构造函数,可用于观察、修改或替换类定义。类装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类上)。
类装饰器的表达式将在运行时作为函数调用,被装饰类的构造函数作为唯一参数。
// 类的装饰器
// 装饰器本身就是一个函数
// 类装饰器接收的是一个构造函数
// 装饰器通过 @ 符号来使用
// 类定义的时候去实现
// 写法1
function testDecorator(constructor: any) {
console.log('decorator')
constructor.prototype.getName = () => {
console.log('111')
}
}
// 写法2
function testDecorator1() {
return function (constructor: any) {
console.log('decorator')
constructor.prototype.getName = () => {
console.log('111')
}
}
}
// 写法3
function testDecorator2(flag: boolean) {
if(flag) {
return function (constructor: any) {
console.log('decorator')
constructor.prototype.getName = () => {
console.log('111')
}
}
} else {
return function (constructor: any) {}
}
}
// @testDecorator
// @testDecorator1()
@testDecorator2(false)
class Test {}
const test = new Test();
(<any>test).getName()
优化:
// 写法1 还是不能够提示
function simpleDecorator<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor {
name = 'lee'
getName() {
console.log(this.name)
}
}
}
// @simpleDecorator
// class Test1 {
// name: string
// constructor(name: string) {
// this.name = name
// }
// }
// const test1 = new Test1('dell');
// (<any>test1).getName()
// console.log(test1.name)
// 写法2
function simpleDecorator1() {
return function<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor {
name = 'lee'
getName() {
console.log(this.name)
}
}
}
}
const Test2 = simpleDecorator1()(class {
name: string
constructor(name: string) {
this.name = name
}
})
const test2 = new Test2('dell');
test2.getName()
2.2 方法装饰器
方法装饰器声明在方法声明之前。该装饰器应用于方法的属性描述符,可用于观察、修改或替换方法定义。方法装饰器不能在声明文件、重载或任何其他环境上下文中使用(例如在声明类中)。
// 在类定义的时候 方法就开始装饰
// 普通方法,target 对应的是类的prototype
// 静态方法,target 对应的是类的构造函数
// 写法1
function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
console.log(target, key, descriptor)
}
// 写法2
function getNameDecorator1() {
return function(target: any, key: string, descriptor: PropertyDescriptor) {}
}
class methodTest {
name: string
constructor(name: string) {
this.name = name
}
@getNameDecorator
getName() {
return this.name
}
}
const methTest = new methodTest('huihui')
console.log(methTest.getName())
2.3 属性装饰器
在属性声明之前声明属性装饰器。属性装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。
// target 指向类的prototype
// 可以使用属性装饰器返回
function nameDecorator(target: any, key: string): any {
const descriptor: PropertyDescriptor = {
writable: false
}
return descriptor
}
// name 放在实例上
class keyDecorator {
@nameDecorator
name = 'huihui'
}
const keyName = new keyDecorator()
keyName.name = 'dell'
2.4 访问器装饰器
访问器装饰器声明在访问器声明之前。访问器装饰器应用于访问器的属性描述符,可用于观察、修改或替换访问器的定义。访问器装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。
function visitDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.writable = false
}
class getDecorator {
private _name: string
constructor(name: string) {
this._name = name
}
get name() {
return this._name
}
@visitDecorator
set name(newName) {
this._name = newName
}
}
2.5 参数装饰器
在参数声明之前声明一个参数装饰器。参数装饰器应用于函数,用于类构造函数或方法声明。参数装饰器不能在声明文件、重载或任何其他环境上下文中使用(例如在声明类中)。
// 原型,方法名,参数所在位置索引
function paramDecoratorF(target: any, key: string, paramIndex: number): any {
console.log(target, key, paramIndex)
}
// name 放在实例上
class paramDecorator {
getInfo(@paramDecoratorF name: string, age: number) {
console.log(name, age)
}
}
const param = new paramDecorator()
param.getInfo('huihui', 12)