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')}@testDecoratorclass 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;}};}@testDecoratorclass 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 = falsedescriptor.value = function() {return 'Decorator '}}class Test {name: string;constructor(name: string) {this.name = name}@getNameDecoratorgetName() {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}@visitDecoratorset name(name: string) {this._name = name}}const test = new Test('Jack')// settest.name = '123'// getconsole.log(test.getName()) // 123
6-5 属性的装饰器
参数有所不同(无法接受descriptor)
function nameDecorator(target: any, key: string): any {// target[key] = 'Lee' // 修改的prototyeconst descriptor: PropertyDescriptor = {writable: false}return descriptor;}class Test {@nameDecoratorname = "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)}}@showDataclass 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)}}@showDataclass User {// @Reflect.metadata('data', 'name')@setData('data', 'name')getName() {}@setData('data', 'age')getAge() {}}// name// age
END 202-5-5
