持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情
强烈建议先看完:TypeScript装饰器学习(一)
1. 方法装饰器
1. 定义:顾名思义,装饰类方法的装饰器
2. 示例
// 不带参
// name buy
// decr {
// value: [Function: buy],
// writable: true,
// enumerable: false,
// configurable: true
// }
/**
* @param {any} targetClassPrototype - 目标方法所属类的原型对象
* @param {string} name - 目标方法的名
* @param {PropertyDescriptor} decr - 目标方法的属性描述器
*/
function methodDecorator(targetClassPrototype: any, name: string, decr: PropertyDescriptor) {
console.log('targetClassPrototype:', targetClassPrototype);
console.log('name:', name);
console.log('decr:', decr);
}
// 带参
// targetClassPrototype {}
// param-path: /buy
// name buy
// decr {
// value: [Function: buy],
// writable: true,
// enumerable: false,
// configurable: true
// }
function methodParamsDecorator(path: string) {
console.log('param-path:', path);
return function (targetClassPrototype: any, name: string, decr: PropertyDescriptor) {
console.log('targetClassPrototype:', targetClassPrototype);
console.log('name:', name);
console.log('decr:', decr);
decr.value()
}
}
class CustomerServeice {
name: string = "张三"
constructor() { }
@methodParamsDecorator('/buy')
buy() {
console.log(`${this.name}购买`);
}
pay() {
console.log(`${this.name}付款`);
}
}
3. 方法拦截器
function MethodInterceptor(params: string) {
return function (targetClassPrototype: any, name: string, decr: PropertyDescriptor) {
let temp = decr.value;
decr.value = function (...args: any) {
// 前置拦截
console.log('选择物品');
temp.call(this, args)
// 后置拦截
console.log('吃掉');
}
}
}
class CustomerServeice {
name: string
constructor(name: string) {
this.name = name;
}
@MethodInterceptor('6666')
buy() {
console.log(`${this.name}购买`);
}
pay() {
console.log(`${this.name}付款`);
}
}
let c1 = new CustomerServeice('张三')
// 选择物品
// 张三购买
// 吃掉
c1.buy()
4. 底层实现
/**
* @param {Array} decorators - 装饰器数组,可以为一个类或函数添加多个装饰器
* @param {} target - 在类中表示装饰器所装饰的目标本身,在方法装饰器中表示方法所在类的额原型对象
* @param {} key - 若是装饰在方法上,会传入这个参数,表示方法名,用来获取方法的属性描述器
* @param {} desc
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
// 获取参数个数
var argLength = arguments.length;
// targetInfo装饰器最终所装饰的目标本身
// 参数个数为2,所装饰的是类/构造器参数,targetInfo=target(即参数target,类本身)
// 参数个数为4,所装饰的是方法【参数desc等于null】,targetInfo通过Object.getOwnPropertyDescriptor(target, key)获得该方法的数据属性描述器
// 参数个数为3,所装饰的是方法参数或属性,targetInfo为undefined
var targetInfo = argLength < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc;
// decorator用来保存装饰器数组元素
var decorator;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
// 判断是否为元数据
targetInfo = Reflect.decorate(decorators, target, key, desc);
} else {
// 遍历装饰目标上的所有装饰器,执行顺序为从下往上
for (var i = decorators.length - 1; i >= 0; i--) {
if (decorator = decorators[i]) {
// 如果参数个数少于3【decorator为类装饰器或构造器参数装饰器】,执行decorator(targetInfo)
// 如果参数个数大于3【decorator为方法装饰器】,执行decorator(target, key, targetInfo)
// 如果参数个数等于于3【decorator为方法参数装饰器或属性装饰器】,执行decorator(target, key))
// targetInfo为最终装饰器执行后返回值
targetInfo = (argLength < 3 ? decorator(targetInfo) : argLength > 3 ? decorator(target, key, targetInfo) : decorator(target, key)) || targetInfo
};
}
}
return argLength > 3 && targetInfo && Object.defineProperty(target, key, targetInfo), targetInfo;
};
function MethodInterceptor(params) {
return function (targetClassPrototype, name, decr) {
var temp = decr.value;
decr.value = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
// 前置拦截
console.log('选择物品');
temp.call(this, args);
// 后置拦截
console.log('吃掉');
};
};
}
var CustomerServeice = /** @class */ (function () {
function CustomerServeice(name) {
this.name = name;
}
CustomerServeice.prototype.buy = function () {
console.log(this.name + "\u8D2D\u4E70");
};
CustomerServeice.prototype.pay = function () {
console.log(this.name + "\u4ED8\u6B3E");
};
// 传入四个参数
__decorate([
MethodInterceptor('6666')
], CustomerServeice.prototype, "buy", null);
return CustomerServeice;
}());
var c1 = new CustomerServeice('张三');
// 选择物品
// 张三购买
// 吃掉
c1.buy();
2. 属性装饰器
1. 定义:顾名思义,装饰类属性的装饰器
2. 示例:
function ProperTYDecorator(param: string) {
return function (targetClassPrototype: object, name: string | symbol) {
console.log('targetClassPrototype:', targetClassPrototype);
console.log("name:", name);
Object.defineProperty(targetClassPrototype.constructor, "level", {
configurable: true,
writable: true,
enumerable: false,
value: function () {
console.log('test');
}
})
}
}
class CustomerServeice {
@ProperTYDecorator('6666')
name: string
constructor(name: string) {
this.name = name;
}
buy() {
console.log(`${this.name}购买`);
}
pay() {
console.log(`${this.name}付款`);
}
}
(CustomerServeice as any).level()