摘要:可見參數裝飾器函數需要個參數被裝飾類的原型,裝飾參數所屬的方法名,參數的索引。參數裝飾器不應當用來修改構造器方法或屬性的行為,它只應當用來產生某種元數據。一旦元數據被創建,我們便可以用其它的裝飾器去讀取它。
之前已經分別介紹了方法裝飾器、屬性裝飾器和類裝飾器,這篇文章我們來繼續關注這些話題:
參數裝飾器
裝飾器工廠
我們將圍繞以下這個例子,來探討這些概念:
class Person { public name: string; public surname: string; constructor(name : string, surname : string) { this.name = name; this.surname = surname; } public saySomething(something : string) : string { return this.name + " " + this.surname + " says: " + something; } }參數裝飾器
TypeScript對于參數裝飾器的聲明如下
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;
如下我們為類Person的saySomething方法的參數添加一個參數裝飾器
public saySomething(@logParameter something : string) : string { return this.name + " " + this.surname + " says: " + something; }
最終被編譯為JavaScript的樣子為:
Object.defineProperty(Person.prototype, "saySomething", __decorate( [__param(0, logParameter)], Person.prototype, "saySomething", Object.getOwnPropertyDescriptor(Person.prototype, "saySomething") ) ); return Person;
如果將其和之前的裝飾器比較,是否會發現又使用了Object.defineProperty()方法,那么是否意味著saySomething將被__decorated函數的返回值替換?
我們發現這里有個新函數__param,TypeScript編譯器生成如下:
var __param = this.__param || function (index, decorator) { // 返回一個裝飾器函數 return function (target, key) { // 應用裝飾器(忽略返回值) decorator(target, key, index); } };
如上所示,調用參數裝飾器,其并沒有返回值,這就意味著,函數__decorate的調用返回并沒有覆蓋方法saySomething,也很好理解:參數裝飾器要毛返回。
可見參數裝飾器函數需要3個參數:被裝飾類的原型,裝飾參數所屬的方法名,參數的索引。具體的實現如下:
function logParameter(target: any, key : string, index : number) { var metadataKey = `log_${key}_parameters`; if (Array.isArray(target[metadataKey])) { target[metadataKey].push(index); } else { target[metadataKey] = [index]; } }
其中向類的原型中增加一個新的屬性metadataKey,該屬性值是一個數組,包含所裝飾參數的索引,可以把它當作元數據。
參數裝飾器不應當用來修改構造器、方法或屬性的行為,它只應當用來產生某種元數據。一旦元數據被創建,我們便可以用其它的裝飾器去讀取它。
裝飾器工廠官方TypeScript裝飾器建議定義一個如下的裝飾器工廠:
裝飾器工廠首先是一個函數,它接受任意數量的參數,同時返回如前所述的四種之一特定類型的裝飾器。
雖然已經討論四種裝飾是如何實現及使用的,但還是有一些可以改進的地方,觀察下面的代碼片段:
@logClass class Person { @logProperty public name: string; public surname: string; constructor(name : string, surname : string) { this.name = name; this.surname = surname; } @logMethod public saySomething(@logParameter something : string) : string { return this.name + " " + this.surname + " says: " + something; } }
這里裝飾器的使用是沒問題的,但如果我們可以不關心裝飾器的類型,而在任何地方使用豈不方便,就像下面的樣子:
@log class Person { @log public name: string; public surname: string; constructor(name : string, surname : string) { this.name = name; this.surname = surname; } @log public saySomething(@log something : string) : string { return this.name + " " + this.surname + " says: " + something; } }
這邊是裝飾器工廠的使用訴求,它可以識別具體情況下該使用哪種類型的裝飾器,幸運的是,我們可以通過傳遞給裝飾器的參數來區分它的類型。
function log(...args : any[]) { switch(args.length) { case 1: return logClass.apply(this, args); case 2: return logProperty.apply(this, args); case 3: if(typeof args[2] === "number") { return logParameter.apply(this, args); } return logMethod.apply(this, args); default: throw new Error("Decorators are not valid here!"); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101516.html
摘要:使用裝飾器的方法很簡單在裝飾器名前加字符,寫在想要裝飾的方法上,類似寫注釋的方式裝飾器實際上是一個函數,入參為所裝飾的方法,返回值為裝飾后的方法。經過裝飾過的方法,它依然按照原來的方式執行,只是額外執行了附件的裝飾器函數的功能。 讓我來深入地了解一下TypeScript對于裝飾器模式的實現,以及反射與依賴注入等相關特性。 在Typescript的源代碼中,可以看到裝飾器能用來修飾cla...
摘要:慶幸的是,已經支持反射機制,來看看這個特性吧元數據反射可以通過安裝包來使用元數據反射的若要使用它,我們需要在中設置為,同時添加的引用,同時加載文件。復雜類型序列化的團隊為復雜類型的元數據序列化做出了努力。 本篇內容包括如下部分: 為什么JavaScript中需要反射 元數據反射API 基本類型序列化 復雜類型序列化 為什么JavaScript中需要反射? 關于反射的概念,摘自百度百...
摘要:值得注意的是,的返回值復寫了原始的構造函數,原因是類裝飾器必須返回一個構造器函數。原始構造函數的原型被復制給的原型,以確保在創建一個的新實例時,操作符如愿以償,具體原因可參考鄙人另一篇文章原型與對象。 上一篇文章中,我們討論了TypeScript源碼中關于方法裝飾器的實現,搞明白了如下幾個問題: 裝飾器函數是如何被調用的? 裝飾器函數參數是如何傳入的? __decorate函數干了...
摘要:看了這一章,發現原來是裝飾器,又一新知識。期間,裝飾器會做一些額外的工作。書中介紹了模塊中的三個裝飾器。另一個是,這個裝飾器把函數結果保存了起來,避免傳入相同參數時重復計算。疊放不奇怪,裝飾器返回的就是函數或可調用對象。 在 Web 框架 Flask 中,最常看到的或許是以@app.route開頭的那行代碼。由于還是剛接觸 Flask,所以對這種語法還不熟悉。看了這一章,發現原來是裝飾...
摘要:本文從裝飾模式出發,聊聊中的裝飾器和注解。該函數的函數名。不提供元數據的支持。中的元數據操作可以通過包來實現對于元數據的操作。 ??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經常看到類似于java spring中注解的寫法。本文從裝飾模式出發,聊聊Typescipt中的裝飾器和注解。 什么是裝飾者模式 Typescript中的裝飾器 Typescr...
閱讀 1315·2021-11-15 11:37
閱讀 2571·2021-09-22 10:56
閱讀 3395·2021-09-06 15:11
閱讀 808·2021-08-31 09:45
閱讀 2906·2021-07-28 11:16
閱讀 1813·2019-08-30 15:44
閱讀 481·2019-08-30 13:22
閱讀 3348·2019-08-30 13:18