摘要:可見(jiàn)參數(shù)裝飾器函數(shù)需要個(gè)參數(shù)被裝飾類(lèi)的原型,裝飾參數(shù)所屬的方法名,參數(shù)的索引。參數(shù)裝飾器不應(yīng)當(dāng)用來(lái)修改構(gòu)造器方法或?qū)傩缘男袨?,它只?yīng)當(dāng)用來(lái)產(chǎn)生某種元數(shù)據(jù)。一旦元數(shù)據(jù)被創(chuàng)建,我們便可以用其它的裝飾器去讀取它。
之前已經(jīng)分別介紹了方法裝飾器、屬性裝飾器和類(lèi)裝飾器,這篇文章我們來(lái)繼續(xù)關(guān)注這些話題:
參數(shù)裝飾器
裝飾器工廠
我們將圍繞以下這個(gè)例子,來(lái)探討這些概念:
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; } }參數(shù)裝飾器
TypeScript對(duì)于參數(shù)裝飾器的聲明如下
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol, parameterIndex: number) => void;
如下我們?yōu)轭?lèi)Person的saySomething方法的參數(shù)添加一個(gè)參數(shù)裝飾器
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;
如果將其和之前的裝飾器比較,是否會(huì)發(fā)現(xiàn)又使用了Object.defineProperty()方法,那么是否意味著saySomething將被__decorated函數(shù)的返回值替換?
我們發(fā)現(xiàn)這里有個(gè)新函數(shù)__param,TypeScript編譯器生成如下:
var __param = this.__param || function (index, decorator) { // 返回一個(gè)裝飾器函數(shù) return function (target, key) { // 應(yīng)用裝飾器(忽略返回值) decorator(target, key, index); } };
如上所示,調(diào)用參數(shù)裝飾器,其并沒(méi)有返回值,這就意味著,函數(shù)__decorate的調(diào)用返回并沒(méi)有覆蓋方法saySomething,也很好理解:參數(shù)裝飾器要毛返回。
可見(jiàn)參數(shù)裝飾器函數(shù)需要3個(gè)參數(shù):被裝飾類(lèi)的原型,裝飾參數(shù)所屬的方法名,參數(shù)的索引。具體的實(shí)現(xiàn)如下:
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]; } }
其中向類(lèi)的原型中增加一個(gè)新的屬性metadataKey,該屬性值是一個(gè)數(shù)組,包含所裝飾參數(shù)的索引,可以把它當(dāng)作元數(shù)據(jù)。
參數(shù)裝飾器不應(yīng)當(dāng)用來(lái)修改構(gòu)造器、方法或?qū)傩缘男袨?,它只?yīng)當(dāng)用來(lái)產(chǎn)生某種元數(shù)據(jù)。一旦元數(shù)據(jù)被創(chuàng)建,我們便可以用其它的裝飾器去讀取它。
裝飾器工廠官方TypeScript裝飾器建議定義一個(gè)如下的裝飾器工廠:
裝飾器工廠首先是一個(gè)函數(shù),它接受任意數(shù)量的參數(shù),同時(shí)返回如前所述的四種之一特定類(lèi)型的裝飾器。
雖然已經(jīng)討論四種裝飾是如何實(shí)現(xiàn)及使用的,但還是有一些可以改進(jìn)的地方,觀察下面的代碼片段:
@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; } }
這里裝飾器的使用是沒(méi)問(wèn)題的,但如果我們可以不關(guān)心裝飾器的類(lèi)型,而在任何地方使用豈不方便,就像下面的樣子:
@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; } }
這邊是裝飾器工廠的使用訴求,它可以識(shí)別具體情況下該使用哪種類(lèi)型的裝飾器,幸運(yùn)的是,我們可以通過(guò)傳遞給裝飾器的參數(shù)來(lái)區(qū)分它的類(lèi)型。
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!"); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/101516.html
摘要:使用裝飾器的方法很簡(jiǎn)單在裝飾器名前加字符,寫(xiě)在想要裝飾的方法上,類(lèi)似寫(xiě)注釋的方式裝飾器實(shí)際上是一個(gè)函數(shù),入?yún)樗b飾的方法,返回值為裝飾后的方法。經(jīng)過(guò)裝飾過(guò)的方法,它依然按照原來(lái)的方式執(zhí)行,只是額外執(zhí)行了附件的裝飾器函數(shù)的功能。 讓我來(lái)深入地了解一下TypeScript對(duì)于裝飾器模式的實(shí)現(xiàn),以及反射與依賴(lài)注入等相關(guān)特性。 在Typescript的源代碼中,可以看到裝飾器能用來(lái)修飾cla...
摘要:慶幸的是,已經(jīng)支持反射機(jī)制,來(lái)看看這個(gè)特性吧元數(shù)據(jù)反射可以通過(guò)安裝包來(lái)使用元數(shù)據(jù)反射的若要使用它,我們需要在中設(shè)置為,同時(shí)添加的引用,同時(shí)加載文件。復(fù)雜類(lèi)型序列化的團(tuán)隊(duì)為復(fù)雜類(lèi)型的元數(shù)據(jù)序列化做出了努力。 本篇內(nèi)容包括如下部分: 為什么JavaScript中需要反射 元數(shù)據(jù)反射API 基本類(lèi)型序列化 復(fù)雜類(lèi)型序列化 為什么JavaScript中需要反射? 關(guān)于反射的概念,摘自百度百...
摘要:值得注意的是,的返回值復(fù)寫(xiě)了原始的構(gòu)造函數(shù),原因是類(lèi)裝飾器必須返回一個(gè)構(gòu)造器函數(shù)。原始構(gòu)造函數(shù)的原型被復(fù)制給的原型,以確保在創(chuàng)建一個(gè)的新實(shí)例時(shí),操作符如愿以償,具體原因可參考鄙人另一篇文章原型與對(duì)象。 上一篇文章中,我們討論了TypeScript源碼中關(guān)于方法裝飾器的實(shí)現(xiàn),搞明白了如下幾個(gè)問(wèn)題: 裝飾器函數(shù)是如何被調(diào)用的? 裝飾器函數(shù)參數(shù)是如何傳入的? __decorate函數(shù)干了...
摘要:看了這一章,發(fā)現(xiàn)原來(lái)是裝飾器,又一新知識(shí)。期間,裝飾器會(huì)做一些額外的工作。書(shū)中介紹了模塊中的三個(gè)裝飾器。另一個(gè)是,這個(gè)裝飾器把函數(shù)結(jié)果保存了起來(lái),避免傳入相同參數(shù)時(shí)重復(fù)計(jì)算。疊放不奇怪,裝飾器返回的就是函數(shù)或可調(diào)用對(duì)象。 在 Web 框架 Flask 中,最??吹降幕蛟S是以@app.route開(kāi)頭的那行代碼。由于還是剛接觸 Flask,所以對(duì)這種語(yǔ)法還不熟悉??戳诉@一章,發(fā)現(xiàn)原來(lái)是裝飾...
摘要:本文從裝飾模式出發(fā),聊聊中的裝飾器和注解。該函數(shù)的函數(shù)名。不提供元數(shù)據(jù)的支持。中的元數(shù)據(jù)操作可以通過(guò)包來(lái)實(shí)現(xiàn)對(duì)于元數(shù)據(jù)的操作。 ??隨著Typescript的普及,在KOA2和nestjs等nodejs框架中經(jīng)??吹筋?lèi)似于java spring中注解的寫(xiě)法。本文從裝飾模式出發(fā),聊聊Typescipt中的裝飾器和注解。 什么是裝飾者模式 Typescript中的裝飾器 Typescr...
閱讀 1404·2021-11-15 11:37
閱讀 2762·2021-09-22 10:56
閱讀 3495·2021-09-06 15:11
閱讀 932·2021-08-31 09:45
閱讀 3107·2021-07-28 11:16
閱讀 1921·2019-08-30 15:44
閱讀 605·2019-08-30 13:22
閱讀 3433·2019-08-30 13:18