概念定义:允许向一个现有的对象添加新的功能,同时又不改变其结构。
实现一:ts语法糖最好看官方文档
//方法装饰器 当装饰器 @enumerable(false)被调用时,它会修改属性描述符的enumerable属性。
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
function enumerable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.enumerable = value;
};
}
// 访问器装饰器(@configurable)的例子,应用于Point类的成员上:
class Point {
private _x: number;
private _y: number;
constructor(x: number, y: number) {
this._x = x;
this._y = y;
}
@configurable(false)
get x() { return this._x; }
@configurable(false)
get y() { return this._y; }
}
function configurable(value: boolean) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
descriptor.configurable = value;
};
}
// 属性装饰器当 @format("Hello, %s")被调用时,它添加一条这个属性的元数据,通过reflect-metadata库里的Reflect.metadata函数。 当 getFormat被调用时,它读取格式的元数据。
class Greeter {
@format("Hello, %s")
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
let formatString = getFormat(this, "greeting");
return formatString.replace("%s", this.greeting);
}
}
import "reflect-metadata";
const formatMetadataKey = Symbol("format");
function format(formatString: string) {
return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}
//参数装饰器 @required装饰器添加了元数据实体把参数标记为必需的。 @validate装饰器把greet方法包裹在一个函数里在调用原先的函数前验证函数参数。
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@validate
greet(@required name: string) {
return "Hello " + name + ", " + this.greeting;
}
}
import "reflect-metadata";
const requiredMetadataKey = Symbol("required");
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
existingRequiredParameters.push(parameterIndex);
Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}
function validate(target: any, propertyName: string, descriptor: TypedPropertyDescriptor<Function>) {
let method = descriptor.value;
descriptor.value = function () {
let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
if (requiredParameters) {
for (let parameterIndex of requiredParameters) {
if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
throw new Error("Missing required argument.");
}
}
}
return method.apply(this, arguments);
}
}
/*
* @Description:
* @version: 1.0.0
* @Author: 吴文周
* @Date: 2021-03-31 19:38:15
* @LastEditors: 吴文周
* @LastEditTime: 2021-03-31 19:41:59
*/
import { SyncHook } from 'tapable'
import axios from 'axios'
/**
* 初始化hooks
* @param options 初始化参数
*/
const initHooks = (options: any) => {
const hooks = {
request: new SyncHook(['config', 'error']),
response: new SyncHook(['response', 'error']),
}
if (Array.isArray(options.plugins)) {
for (const plugin of options.plugins) {
if (typeof plugin === 'function') {
plugin.call(hooks)
} else {
plugin.apply(hooks)
}
}
}
return hooks
}
/**
* 封装的请求方法
* @param options 初始化参数
*/
export const request = (options: any) => {
const hooks = initHooks(options)
const http = axios.create()
http.interceptors.request.use(
(config) => {
hooks.request.call(config, '')
return config
},
(error) => {
hooks.request.call('', error)
return Promise.reject(error)
},
)
http.interceptors.response.use(
(response) => {
hooks.response.call(response, '')
return response
},
(error) => {
hooks.response.call('', error)
return Promise.reject(error)
},
)
const request = (args: any) => {
return new Promise((resolve, reject) => {
http
.get('http://localhost:3000/xx', {//测试代码
// params: params ? params : "",
})
.then((res) => {
try {
const data = res.hasOwnProperty('data') ? res.data : {}
resolve(data)
} catch (error) {
resolve(error)
}
})
.catch((err) => {
reject(err)
})
})
}
return request
}
class Test {
constructor() {}
apply(hooks) {
hooks.request.tap('request', (config, error) => {
if (error) {
console.log(error)
} else {
console.log('Test请求正常的')
}
})
hooks.response.tap('response', (response, error) => {
if (error) {
console.log(error)
} else {
console.log(response)
}
})
}
}
class Test1 {
constructor() {}
apply(hooks) {
hooks.request.tap('request', (config, error) => {
if (error) {
console.log(error)
} else {
console.log('Test1请求正常的')
}
})
hooks.response.tap('response', (response, error) => {
if (error) {
console.log(error)
} else {
console.log(response)
}
})
}
}
//插件Test,Test1
var options = {
plugins: [new Test(), new Test1()],
}
// 实例化对象
const r = index.request(options)
// 调用请求,插件扩展能力
r()
.then((data) => {
console.log(data)
})
.catch((err) => {
console.log(err)
})