6-1 类的装饰器(1)
“dev”: “ts-node ./src/index.ts”
装饰器, 本身是一个函数,
使用?通过@符号来使用
参数?构造函数
执行顺序?先近后远
添加配置
"experimentalDecorators": true,
"emitDecoratorMetadata": true
index.ts
function testDecorator(constructor: any) {
constructor.prototype.getName = () => {
console.log('hello')
}
// console.log('Decorator')
}
@testDecorator
class Test {}
const test = new Test()
// 方式二, 函数装饰器作为返回函数, 且装饰器可以传递参数
function testDecorator() {
return function(constructor: any) {
constructor.prototype.getName = () => {
console.log('hello')
}
}
}
@testDecorator()
class Test {}
6-2 类的装饰器(2)
构造函数new (…args: any[]) => any
function testDecorator<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor {
name = 'Lcuy'
getName() {
return this.name;
}
};
}
@testDecorator
class Test {
name: string;
constructor(name: string) {
this.name = name
}
}
const test = new Test('Jack')
console.log(test.getName())
执行顺序?
修正错误提示
function testDecorator() {
return function<T extends new (...args: any[]) => any>(constructor: T) {
return class extends constructor {
name = 'Lcuy'
getName() {
return this.name;
}
};
}
}
const Test = testDecorator() {
class {
name: string;
constructor(name: string) {
this.name = name
}
}
}
const test = new Test('Jack')
console.log(test.getName())
6-3 方法装饰器
// 普通方法,target 对应类的prototype, key需要装饰的方法的名字
// 静态方法, target 对应的是类的构造函数,
function getNameDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
descriptor.writable = false
descriptor.value = function() {
return 'Decorator '
}
}
class Test {
name: string;
constructor(name: string) {
this.name = name
}
@getNameDecorator
getName() {
return this.name;
}
}
const test = new Test('Jack')
// 若修改方法
test.getName = () => {
return "abc"
}
console.log(test.getName())
6-4 访问器的装饰器
访问器? get/set 访问器, 但是不能同时使用装饰器
function visitDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
// descriptor.writable = false
}
class Test {
private _name: string;
constructor(name: string) {
this._name = name
}
get name() {
return this._name
}
@visitDecorator
set name(name: string) {
this._name = name
}
}
const test = new Test('Jack')
// set
test.name = '123'
// get
console.log(test.getName()) // 123
6-5 属性的装饰器
参数有所不同(无法接受descriptor)
function nameDecorator(target: any, key: string): any {
// target[key] = 'Lee' // 修改的prototye
const descriptor: PropertyDescriptor = {
writable: false
}
return descriptor;
}
class Test {
@nameDecorator
name = "Jack"
}
const test = new Test()
test.name = '123'
console.log(test.getName()) // 123
6-6 参数装饰器
// 原型, 方法, 参数所在的位置
function paramDecorator(target: any, key: string, paramIndex: number) {
}
class Test {
getInfo(@paramDecorator name: string, age: number) {
}
}
const test = new Test()
test.getInfo("Jack", 28)
6-7 装饰器应用
需求: 错误捕获封装到装饰器中
const userInfo: any = undefined;
function catchError(msg: string) {
return function(target: any, key: string, descriptor: PropertyDescriptor) {
const fn = descriptor.value
// 重写函数内容
descriptor.value = function() {
try {
fn();
} catch (e) {
console.error(msg)
}
}
}
}
class Test {
@catchError("name undefined")
getName() {
return userInfo.name;
}
@catchError("age undefined")
getAge() {
return userInfo.age;
}
}
6-8 reflect-metadata
yarn add reflect-metadata
应用1, 定义原(?)数据
import 'reflect-metadata'
const user = {
name: 'Jack'
}
Reflect.defineMetadata('age', 28, user)
console.log(Reflect.getMetadata('age', user))
应用2, 原数据定义到类上
import 'reflect-metadata'
@Reflect.metadata('age', 16)
class User = {
name: 'Jack'
}
console.log(Reflect.getMetadata('age', User))
应用, 原数据定义到属性上
import 'reflect-metadata'
class User = {
@Reflect.metadata('age', 16)
name: 'Jack'
}
console.log(Reflect.getMetadata('age', User.prototype, 'age'))
应用, 原数据定义到方法上
import 'reflect-metadata'
class User {
@Reflect.metadata('age', 16)
getName() {}
}
console.log(Reflect.getMetadata('age', User.prototype, 'getName'))
常见方法
- metadata
- defineMetadata
- hasMetadata
- hasOwnMetadata, 区别在于是否来自于继承
- hasMetadataKeys(‘age’, User.prototype, ‘age’), 获取原数据的key
- hasOwnMetadataKeys
6-9 装饰器的执行顺序
方法装饰器优先于类装饰器执行
import 'reflect-metadata'
function showData(target: typeof User) {
for (let key in target.prototype) {
const data = Reflect.getMetadata('data', target.prototype, key)
console.log(data)
}
}
@showData
class User {
@Reflect.metadata('data', 'name')
getName() {}
@Reflect.metadata('data', 'age')
getAge() {}
}
// name
// age
创建自己的装饰器
import 'reflect-metadata'
function showData(target: typeof User) {
for (let key in target.prototype) {
const data = Reflect.getMetadata('data', target.prototype, key)
console.log(data)
}
}
function setData(dataKey: string, mag: string) {
return function(target: User, key: string) {
Reflect.defineMetadata(dataKey, msg, target, key)
}
}
@showData
class User {
// @Reflect.metadata('data', 'name')
@setData('data', 'name')
getName() {}
@setData('data', 'age')
getAge() {}
}
// name
// age
END 202-5-5