有网站域名及空间 别人帮建网站,做网站ps建立多大的画布,企业信用信息网公示网官网查询,国内出版社网站建设TypeScript中的装饰器#x1f44f;序言#x1f609;一、类的装饰器1、什么是装饰器2、装饰器的特点3、几种类的装饰器#xff08;1#xff09;执行顺序#xff08;2#xff09;参数判断#xff08;3#xff09;装饰器标准写法#x1f910;二、类的其他装饰器1、方法装…
TypeScript中的装饰器序言一、类的装饰器1、什么是装饰器2、装饰器的特点3、几种类的装饰器1执行顺序2参数判断3装饰器标准写法二、类的其他装饰器1、方法装饰器2、访问器的装饰器3、属性的装饰器4、参数装饰器三、装饰器实际使用的小例子四、结束语 往期推荐序言
在 ts 中有一个经常被我们熟用但是又很少去注意的一个知识点装饰器。那在下文中将讲解类的装饰器一起类装饰器中的几种其他的装饰器。
下面开始本文的讲解~
一、类的装饰器
1、什么是装饰器
首先我们先来讲 TypeScript 中类的装饰器是什么。
装饰器实际上是一种对类的修饰工具。比如说某一天可能有个女孩子想要出去逛街那么她可能会画个美美的妆出门。因此我们可以把装饰器视为是化妆的这个过程也就是一个美化的过程。
现在就是假设我们有一个类然后呢要对它额外进行一些修饰这个就是装饰器要干的事情了。
2、装饰器的特点
首先我们需要先来了解装饰器的几个特点。具体如下
装饰器本身就是一个函数装饰器接收的参数是构造函数装饰器通过 符号来进行使用。
依据以上这几个特点下面我们来了解几种类的装饰器。
3、几种类的装饰器
1执行顺序
// 第一个装饰器
function testDecorator(constructor: any) {console.log(decorator);
}// 第二个装饰器
function testDecorator1(constructor: any) {console.log(decorator1);
}// 装饰器执行的时候是从下到上从右到左的顺序
testDecorator
testDecorator1
class Test {}const test new Test(); // decorator1 decorator装饰器执行的时候是从下到上从右到左的顺序。
2参数判断
我们如何让类装饰器接收一个参数呢来看一段代码
// 外面再包一层函数
function testDecorator(flag: boolean) {// 工厂模式if (flag) {return function (constructor: any) {constructor.prototype.getName () {console.log(Monday);};};} else {return function (constructor: any) {};}
}testDecorator(true)
class Test {}const test new Test();
(test as any).getName(); // Monday通过上面这段代码我们可以了解到我们通过对类装饰器的外部再包上一层函数这其实有点像柯里化的形式之后通过外部的这个函数进行传参也就是上面代码中的 flag 。最终类装饰器返回一个函数作为结果顺利地进行传参。
3装饰器标准写法
上面的两个装饰器属于两个比较简单和不太规范的装饰器。下面我们来展现一种比较标准的写法
function testDecorator() {return function T extends new (...args: any[]) any(constructor: T) {return class extends constructor {name Tuesday;getName() {return this.name;}};};
}const Test testDecorator()(class {name: string;constructor(name: string) {this.name name;}}
);const test new Test(Monday);
console.log(test.getName()); // Tuesday
在上面的代码中 (...args: any[]) any 是一个函数返回值是一个对象的类型。这个函数会接收很多参数函数把这些参数合并到一起变成一个数组也就是 ...args 。那 T extends new (...args: any[]) any 是什么意思呢意思是 T 可以通过 new (...args: any[]) any 这种类型的构造函数给实例化出来。所以 T 现在可以理解为是一个类或者是 constructor 这样的一个构造函数。
最终我们通过 testDecorator()() 这样的方式让 test 实例可以访问到 getName() 方法并打印出 Tuesday 。
二、类的其他装饰器
1、方法装饰器
这里我想要强调的一个问题是大家觉得类装饰器的执行时刻是什么样的类装饰器在类定义完成之后就可以立即对类进行一个装饰。
那方法装饰器是什么样的呢
方法装饰器跟类装饰器也是一样的。它会等类创建好了之后立即地把方法去做一个修改。
很多小伙伴可能会误认为我是不是得实例化的时候才会对方法去做一个装饰呢其实不是这样的只要在定义完类以后类就会帮助我们对类的方法去做一个装饰。先来看一段代码
// 普通方法 target 对应的是类的 prototype
// 静态方法 target 对应的是类的 构造函数
function getNameDecorator(target: any,key: string,descriptor: PropertyDescriptor
) {// console.log(target);// descriptor的作用对方法中的属性做一些编辑descriptor.writable true;// 通过调用 .value 的方式可以对原来的方法做一些变更descriptor.value function () {return decorator;};
}class Test {name: string;constructor(name: string) {this.name name;}getNameDecoratorgetName() {return this.name;}
}const test new Test(Monday);
test.getName () {return 123;
};
console.log(test.getName()); // decorator
大家先看上面这段代码可能有的小伙伴会觉得最终打印的是 123 。但其实因为我们对方法进行了装饰所以最终打印的结果是 decorator 。
因此一个装饰器对一个方法做完装饰之后就可以多做很多事情了。包括原型targetkey值 和 descriptor 都可以对方法做很多修改。
2、访问器的装饰器
现在我们来学习类里面中访问器的装饰器。我们先来看一段代码
function visitDecorator(target: any,key: string,descriptor: PropertyDescriptor
) {// console.log(123);
}class Test {private _name: string;constructor(name: string) {this._name name;}// 这里不能写visitDecorator同时写两个会引发报错get name() {return this._name;}visitDecoratorset name(name: string) {this._name name;}
}const test new Test(Monday);
test.name Tuesday;
console.log(test.name); // Tuesday
其中 visitDecorator 是一个访问器装饰器。我们现在来解释下上面代码中的运行路径。
第一部分 test.name Tuesday 走的是 set 方法把 Tuesday 这个值赋值给 name 。之后等到我们运行 console.log 的时候就是去调用 get 方法所以最终打印出来的也就是 Tuesday 而不是 Monday 。
3、属性的装饰器
我们先来看第一种属性的装饰器。具体代码如下
function nameDecorator(target: any, key: string): any {const descriptor: PropertyDescriptor {writable: true,};return descriptor;
}class Test {nameDecoratorname Monday;
}const test new Test();
test.name Tuesday;
console.log(test.name); // Tuesday
属性装饰器的写法也是一个 decorator 的形式即上述代码中的 nameDecorator 。这个装饰器接收两个参数分别是 原型target 和 属性的名字key 。在这里我们可以返回一个 descriptor 来替换掉属性原始的 descriptor 。替换完成之后最终打印 Tuesday 。 继续我们来看第二种装饰器。具体代码如下
// 该装饰器无法直接修改实例上的属性值(name)而只能修改原型上的属性值(name)
function nameDecorator(target: any, key: string): any {target[key] Tuesday;
}// name存储在类的实例上
class Test {nameDecoratorname Monday;
}const test new Test();
test.name Hello~;
console.log((test as any).name); // Hello~
console.log((test as any).__proto__.name); // Tuesday这种类型的装饰器中值得注意的点是 nameDecorator 只能用来修改原型上的属性值而无法直接修改实例上的属性值。
4、参数装饰器
上面我们讲到了对类里面的方法、访问器和属性做修饰现在我们再来了解一种新的装饰器对类里面的方法中的参数做修饰。先来看一段代码
// 原型方法名参数所在的位置
function paramDecorator(target: any, key: string, paramIndex: number): any {console.log(target, key, paramIndex); // Test { getInfo: [Function] } , getInfo , 1(参数所在位置是第2个位置)
}class Test {getInfo(name: string, paramDecorator age: number) {console.log(name, age);}
}const test new Test();
test.getInfo(Monday, 18); // Monday 18
大家可以看到通过对方法中的参数进行装饰我们可以获取到装饰器的原型方法名和参数所在的位置这个就是参数装饰器。
三、装饰器实际使用的小例子
上面我们讲到了很多种装饰器相关的原理知识现在我们用一个实际使用的例子来带大家更好的使用装饰器。先看一段代码
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.log(msg);}};};
}class Test {catchError(userInfo.name 不存在)getName() {return userInfo.name;}catchError(userInfo.age 不存在)getAge() {return userInfo.age;}catchError(userInfo.gender 不存在)getGender() {return userInfo.gender;}
}const test new Test();
test.getName(); // userInfo.name 不存在
test.getAge(); // userInfo.age 不存在
test.getGender(); // userInfo.gender 不存在
在上面的代码中我们做的是捕获异常的一个功能。通过封装 catchError 装饰器来对我们最终使用的三个方法getName 、 getAge 和 getGender 对这三个方法进行异常捕获。
以上算是对装饰器的一次小小的实践后续深入学习可以再参考一些书籍去多练习。
四、结束语
在上面的文章中我们讲解了装饰器中最基础的类装饰器以及类装饰器中的4中其他类型的装饰器。最后我们还用了一个小例子去简单地了解了装饰器在实际应用中的一些操作。
到这里关于装饰器的学习就接近尾声啦不知道小伙伴们对装饰器又有了一些新的了解呢
如果您觉得这篇文章有帮助到您的的话不妨点赞支持一下哟~~
我们下期再见 往期推荐
TypeScript从0到入门带你进入类型的世界