文章目录
一、装饰器(Decorator)
主要用来扩展类和类的方法
1.类装饰器( ClassDecorator)
创建一个装饰器工厂函数:创建一个接受参数的函数,它将返回一个装饰器函数。装饰器函数将接收类的构造函数作为参数,并可以在装饰器函数内部访问类的属性和方法。
在类前使用装饰器:使用 @ 符号,后跟装饰器工厂函数的调用,将装饰器应用于类。
//target构造函数
const base: ClassDecorator = (target: any) => {
console.log(target);
target.prototype.__xiaowu = '琳'
target.prototype.fn = () => {
console.log('hello,world');
}
}
// 第一种方法
@base
class Http {
}
const http: any = new Http()
// 第二种方法
base(Http) //向下兼容
http.fn()
console.log(http.__xiaowu);
2.方法装饰器 (MethodDecorator)
import 'reflect-metadata'
import axios from 'axios'
const Get = (url: string) => {
const fn: MethodDecorator = (target, _: any, descriptor: PropertyDescriptor) => {
const key = Reflect.getMetadata('key', target)
axios.get(url).then(res => {
descriptor.value(key ? res.data[key] : res.data)
})
}
return fn
}
const Result = () => {
const fn: ParameterDecorator = (target, key, index) => {
console.log(target, key, index, "111"); //index为Result所在的位置
Reflect.defineMetadata('key', 'result', target)
}
return fn
}
const Name: PropertyDecorator = (target, key) => {
console.log(target, key);
}
class Http {
@Name
// 属性装饰器
xiaoman: string
constructor() {
this.xiaoman = '小曼'
}
//方法装饰器
@Get('https://api.apiopen.top/api/getHaoKanVideo?paage=0&size=10')
//参数装饰器
getList(@Result() data: any) {
console.log(data, "data");
}
// @post() 同理
// create() {
// }
}
const http: any = new Http()
console.log(http);
3.参数装饰器 (ParameterDecorator)
//见上
4.参数装饰器 (PropertyDecorator)
//见上
5.装饰器工厂
定义一个装饰器工厂函数,它接受任意个参数,并返回一个装饰器函数。装饰器函数接受一个参数,即被装饰的类。
在装饰器函数内部,可以通过修改参数的原型对象来对类进行装饰。
const base = (name: string) => {
// 函数柯里化,新增自己传进来的值,外面的函数接收自定义参数,里面的函数返回值
// const fn: ClassDecorator = (target: any) => {
// target.prototype.aa = function () {
// console.log(name);
// };
// }
// return fn
return function (target: any) {
// 修改原型对象,添加一个greeting方法
target.prototype.aa = function () {
console.log(name);
};
}
}
@base('xiaoyu')
class Http {
}
const http: any = new Http()
http.aa()
二、命名空间(namespace)
在TypeScript中,命名空间(Namespace)是用来组织和管理代码的一种方式。可以将相似的功能或相关的类、接口、函数等放到同一个命名空间中,以便更好地组织和管理代码。
test.ts中
namespace Test {
export let a = 1
export const add = (a: number, b: number) => a + b
export namespace Test2 {
export let b = 14
}
}
namespace Test {
export let v = 2
}
//使用文件中
import { Test } from './test'
import a = Test.add
console.log(a(1, 2));
三、混入
1.对象混入
interface A {
age: number
}
interface B {
name: string
}
let a: A = {
age: 18
}
let b: B = {
name: '张灿'
}
// 1、 扩展运算符 浅拷贝,返回新的类型
let c = { ...a, ...b }
console.log(c, "c");
// 2、Object.assign 浅拷贝 返回交叉类型
let c1 = Object.assign({}, a, b)
console.log(c1);
2.类混入
是一种将多个类组合在一起创建一个新类的方法。它允许我们在不使用继承的情况下将类的功能组合在一起,以便在不同的类之间共享和重用代码。
class Logger {
log(msg: string) {
console.log(msg);
}
}
class Html {
render() {
console.log('22222');
}
}
class App {
run() {
console.log('run');
}
}
type Custructor<T> = new (...args: any[]) => T
function pluginMinxins<T extends Custructor<App>>(base: T) {
return class extends base {
private Logger = new Logger()
private Html = new Html()
constructor(...args: any[]) {
super(...args)
this.Logger = new Logger()
this.Html = new Html()
}
run(): void {
this.Logger.log('run')
}
render() {
this.Logger.log('render')
this.Html.render()
this.Logger.log('run')
}
}
}
const mixins = pluginMinxins(App)
const app = new mixins()
app.render() //输出render,2222.run
四、Reflect Metadata得API
使用Reflect.defineMetadata()时,需要在tsconfig.json中配置:
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
简单介绍下:Reflect.defineMetadata()是一个方法,用于定义元数据(metadata)。元数据是关于数据的数据,用于描述数据的特征和属性。在JavaScript中,元数据可以通过Reflect.defineMetadata方法添加到对象或函数上,并可以通过Reflect.getMetadata方法获取。
metadataKey: 用于存储和检索元数据的键;
metadataValue: 元数据的值;
target: 要在其上定义元数据的目标对象;
propertyKey: 目标对象上的属性;
import 'reflect-metadata'
// 元数据的命令式定义,定义对象或属性的元数据
Reflect.defineMetadata(metadataKey, metadataValue, target)
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)
// 检查对象或属性的原型链上是否存在元数据键
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
// 检查对象或属性是否存在自己的元数据键
let result = Reflect.hasMetadata(metadataKey, target)
let result = Reflect.hasMetadata(metadataKey, target, propertyKey)
// 获取对象或属性原型链上元数据键的元数据值
let result = Reflect.getMetadata(metadataKey, target)
let result = Reflect.getMetadata(metadataKey, target, propertyKey)
// 获取对象或属性的自己的元数据键的元数据值
let result = Reflect.getOwnMetadata(metadataKey, target)
let result = Reflect.getOwnMetadata(metadataKey, target, propertyKey)
// 获取对象或属性原型链上的所有元数据键
let result = Reflect.getMetadataKeys(target)
let result = Reflect.getMetadataKeys(target, propertyKey)
// 获取对象或属性的所有自己的元数据键
let result = Reflect.getOwnMetadataKeys(target)
let result = Reflect.getOwnMetadataKeys(target, propertyKey)
// 从对象或属性中删除元数据
let result = Reflect.deleteMetadata(metadataKey, target)
let result = Reflect.deleteMetadata(metadataKey, target, propertyKey)
// 通过装饰器将元数据应用于构造函数
@Reflect.metadata(metadataKey, metadataValue)
class C {
// 通过装饰器将元数据应用于方法(属性)
@Reflect.metadata(metadataKey, metadataValue)
method() {
}
}
总结
参考链接:【TypeScript 教程】Reflect Metadata
最后:如果有问题或不理解的地方请大家指出,谢谢大家~