【前端】你好,我叫TypeScript (五)裝飾器
1.什么是裝飾器
裝飾器是一種特殊類型的聲明,它能夠被附加到類聲明,方法,訪問符,屬性和參數(shù)上。
- 裝飾器是一個表達式
- 表達式被執(zhí)行后,返回一個函數(shù)
- 函數(shù)的輸入?yún)?shù)為:target,name和descriptor
- 執(zhí)行函數(shù)后,可能返回descriptor對象,用于配置target對象
裝飾器使用@expression形式,expression求值后必須返回一個函數(shù),他會在運行時被調(diào)用,被裝飾的聲明信息作為參數(shù)傳入。
例如:
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- // 使用裝飾器
- class Boat{
- color: string = "yellow";
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @testDecorator
- pilot(): void{
- console.log("swish");
- }
- }
- // 實例化
- const boat = new Boat();
- boat.pilot();
- console.log(boat.formattedColor);
運行得到:
- Target: {}
- key: pilot
- swish
- this boat color is yellow
2.裝飾器分類
裝飾器根據(jù)其所裝飾的類型分為以下一種:
- 類裝飾器
- 屬性裝飾器
- 方法裝飾器
- 參數(shù)裝飾器
若要啟用實驗性的裝飾器特性,你必須在命令行或tsconfig.json里啟用experimentalDecorators編譯器選項:
命令行:
- tsc --target ES5 --experimentalDecorators
tsconfig.json:
- {
- "compilerOptions": {
- "target": "ES5",
- "experimentalDecorators": true
- }
- }
2.1 類裝飾器
類裝飾器用于類構(gòu)造函數(shù),進行監(jiān)聽、修改或替換類定義,在類聲明之前進行聲明(緊挨著類聲明)。
切記:
- 類裝飾器不能用在聲明文件中(.d.ts),也不能用在任何外部上下文中。
- 類裝飾器表達式會在運行時當作函數(shù)被調(diào)用,類的構(gòu)造函數(shù)作為其唯一的參數(shù)。
- 如果類裝飾器返回一個值,它會使用提供的構(gòu)造函數(shù)來替換類的聲明。
- 如果你要返回一個新的構(gòu)造函數(shù),你必須注意處理好原來的原型鏈。在運行時的裝飾器調(diào)用邏輯中不會為你做這些。
類裝飾器聲明:
- declare type ClassDecorator = <TFunction extends Function>(
- target: TFunction
- )=>TFunction | void;
類裝飾器顧名思義,就是⽤來裝飾類的。它接收⼀個參數(shù):
- target: TFunction - 被裝飾的類
栗子:
- // 類裝飾器
- function classDecorator(constructor: typeof Boat){
- console.log(constructor);
- }
- // 使用類裝飾器
- @classDecorator
- class Boat{
- }
運行結(jié)果:
- [class Boat]
2.2 方法裝飾器
方法裝飾器用于方法的屬性描述符,可以進行監(jiān)聽、修改或替換方法定義,在待修飾方法聲明前進行聲明。方法裝飾器不能用在聲明文件(.d.ts),重載或者任何外部上下文中。
方法裝飾器表達式會在運行時當作函數(shù)被調(diào)用,傳入下列3個參數(shù):
- target:被裝飾的類
- key: 方法名
- descriptor: 屬性描述符
「注意:如果代碼輸出目標版本小于ES5,屬性描述符將會是undefined?!?/p>
如果方法裝飾器返回一個值,它會被用作方法的屬性描述符。
舉個栗子:
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- function logError(errorMessage: string){
- return function(target: any, key: string, desc: PropertyDescriptor){
- const method = desc.value;
- desc.value = function(){
- try {
- method();
- }catch(err){
- console.log(errorMessage);
- }
- }
- }
- }
- // 使用裝飾器
- class Boat{
- color: string = "yellow";
- @testDecorator
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @logError("Oops boat was sunk in ocean")
- pilot(): void{
- throw new Error()
- console.log("swish");
- }
- }
- // 實例化
- const boat = new Boat();
- boat.pilot();
運行得到:
- Target: {}
- key: formattedColor
- Oops boat was sunk in ocean
2.3 屬性裝飾器
屬性裝飾器屬性描述符只能用來監(jiān)視類中是否聲明了某個名字的屬性,在屬性聲明前進行聲明。
屬性裝飾器表達式會在運行時當做函數(shù)進行調(diào)用,傳入兩個參數(shù):
- target: 被裝飾的類
- key: 被裝飾類的屬性名字
注意:屬性描述符不作為參數(shù)傳入屬性裝飾器。因為目前還沒有辦法在定義一個原型對象時描述一個實例屬性,并且沒有辦法進行建議監(jiān)聽或修改一個屬性的初始化方法。
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- function logError(errorMessage: string){
- return function(target: any, key: string, desc: PropertyDescriptor){
- const method = desc.value;
- desc.value = function(){
- try {
- method();
- }catch(err){
- console.log(errorMessage);
- }
- }
- }
- }
- // 使用裝飾器
- class Boat{
- @testDecorator
- color: string = "yellow";
- // @testDecorator
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @logError("Oops boat was sunk in ocean")
- pilot(): void{
- throw new Error()
- console.log("swish");
- }
- }
運行結(jié)果:
- Target: {}
- key: color
2.4 參數(shù)裝飾器
參數(shù)裝飾器用于類構(gòu)造函數(shù)或方法聲明。接收三個參數(shù):
- target: 被裝飾的類
- key:方法名
- index:方法中的參數(shù)索引值
- // 定義裝飾器
- function testDecorator(target: any, key: string): void {
- console.log("Target: ", target );
- console.log("key: ", key);
- }
- function logError(errorMessage: string){
- return function(target: any, key: string, desc: PropertyDescriptor){
- const method = desc.value;
- desc.value = function(){
- try {
- method();
- }catch(err){
- console.log(errorMessage);
- }
- }
- }
- }
- // 參數(shù)裝飾器
- function parameterDecorator(target: any, key: string, index: number){
- console.log(key, index);
- }
- // 使用裝飾器
- class Boat{
- @testDecorator
- color: string = "yellow";
- // @testDecorator
- get formattedColor(): string{
- return `this boat color is ${this.color}`;
- }
- @logError("Oops boat was sunk in ocean")
- pilot(): void{
- throw new Error()
- console.log("swish");
- }
- fast(
- @parameterDecorator speed: string,
- @parameterDecorator generateWake: boolean
- ): void{
- if(speed === "fast"){
- console.log("swish");
- }else{
- console.log("nothing");
- }
- }
- }
運行結(jié)果:
- Target: {}
- key: color
- fast 1
- fast 0
小結(jié)
我們看到裝飾器很方便為我們結(jié)果了許多問題。裝飾器根據(jù)其裝飾的對象不同,分為:類裝飾器、屬性裝飾器、方法裝飾器、參數(shù)裝飾器。