在C#里面如果想要不直接修改類或方法,但給類或方法添加一些額外的信息或功能,可以想到用Attribute
,這是一個(gè)十分方便的功能裝飾器。
用TypeScript同樣也可以利用裝飾器來給類、函數(shù)、屬性以及參數(shù)添加附加功能,裝飾器是ES7的一個(gè)提案,在TypeScript里已經(jīng)有實(shí)現(xiàn)可用,不過需要在tsconfig.json
里啟用experimentalDecorators
。
創(chuàng)新互聯(lián)是專業(yè)的射洪網(wǎng)站建設(shè)公司,射洪接單;提供成都網(wǎng)站建設(shè)、網(wǎng)站制作,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行射洪網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
"compilerOptions": { ..., // other options "experimentalDecorators": true}
TypeScript中裝飾器可以應(yīng)用到類、方法、屬性及函數(shù)參數(shù)上,而且可以同時(shí)應(yīng)用多個(gè)。
裝飾器的寫法是@name()
,()
可以不要,也可以在里面寫一些參數(shù)。
@Testable @Log('controller')class Controller{ @GET getContent(@QueryParam arg: string): string{ return ''; } }
裝飾器根據(jù)實(shí)現(xiàn)可以分兩種:
一種是不帶括號(hào),和屬性一樣,如@Testable
。
function Testable(target: Function) { // 類、方法、屬性、方法參數(shù)的參數(shù)各不相同 //這里可以記錄一些信息到target,或者針對(duì)target做一些處理,如seal}
另外一種是帶括號(hào)的,和函數(shù)一樣,如@Log('controller')
,實(shí)現(xiàn)函數(shù)里的參數(shù)就是括號(hào)里的參數(shù),而且需要返回一個(gè)function
。
function Log(name: string) { // name就是傳進(jìn)來的參數(shù)'controller' return function(target: Function) { // 類、方法、屬性、方法參數(shù)的參數(shù)各不相同 // 這里可以根據(jù)name和target來做一些處理 } }
上面的(target: Function)
其實(shí)就是類的裝飾器參數(shù),指向的是類的構(gòu)造函數(shù),如果想給類加一個(gè)簡單的seal功能,可以這樣做:
function sealed(target: Function) { Object.seal(target); Object.seal(target.prototype); } @sealedclass Test{ } Test.prototype.test = ''; // 運(yùn)行時(shí)出錯(cuò),不能添加
上面的sealed
就是類的裝飾器,target
指構(gòu)造函數(shù),類裝飾器就這么一個(gè)參數(shù)。
方法裝飾器的使用方法和類裝飾器類似,只是參數(shù)不一樣,方法裝飾器有三個(gè)參數(shù):
如果裝飾的是靜態(tài)方法,則是類的構(gòu)造函數(shù),如果是實(shí)例方法則是類的原型。
方法的名字。
方法的PropertyDescriptor
。PropertyDescriptor
即屬性描述符,有
configurable 是否可以配置,如動(dòng)態(tài)添加刪除函數(shù)屬性之類
writable 是否可寫,可以用來設(shè)置只讀屬性
enumerable 是否可枚舉,即是否能在for...in
中能枚舉到
value 對(duì)象或?qū)傩缘闹?/p>
有了這些參數(shù)就可以很好的給方法添加一些功能,比如下面實(shí)現(xiàn)類型WebApi里的Get的路由:
const Router = Symbol(); // 唯一key,用來存裝飾器的信息function GET(path?: string) { // GET帶了個(gè)可選參數(shù) return (target: any, name: string) => setMethodDecorator(target, name, 'GET', path); }//把method和path存起來,路由查找的時(shí)候就可以用了function setMethodDecorator(target: any, name: string, method: string, path?: string){ target[Router] = target[Router] || {}; target[Router][name] = target[Router][name] || {}; target[Router][name].method = method; target[Router][name].path = path; }// 通過PropertyDescriptor來設(shè)置enumerablefunction Enumerable(enumerable: boolean) { return (target: any, name: string, descriptor: PropertyDescriptor) => { descriptor.enumerable = enumerable; }; }class Controller{ @GET @Enumerable(true) getContent(arg: string): string{ return ''; } }
方法參數(shù)同樣可以有裝飾器,同樣有三個(gè)參數(shù),前兩個(gè)參數(shù)和方法的一致,最后一個(gè)參數(shù)是所裝飾的參數(shù)的位置。
能過參數(shù)裝飾器可以給方法動(dòng)態(tài)的檢查或設(shè)置參數(shù)值,下面是檢查參數(shù)是否為空,為空則拋出異常。
const CheckNullKey = Symbol();const Router = Symbol();// 把CheckNull裝飾的參數(shù)存起來function CheckNull(target: any, name: string, index: number) { target[Router] = target[Router] || {}; target[Router][name] = target[Router][name] || {}; target[Router][name].params = target[Router][name].params || []; target[Router][name].params[index] = CheckNullKey; }// 找出CheckNull的參數(shù),并檢查參數(shù)值,為空則拋異常,否則繼續(xù)執(zhí)行方法function Check(target: any, name: string, descriptor: PropertyDescriptor) { let method = descriptor.value; descriptor.value = function () { let params = target[Router][name].params; if (params) { for (let index = 0; index < params.length; index++) { if (params[index] == CheckNullKey && // 找到CheckNull的參數(shù)并拋異常 (arguments[index] === undefined || arguments[index] === null)) { throw new Error("Missing required argument."); } } } return method.apply(this, arguments); } }class Controller{ @Check getContent(@CheckNull id: string): string{ console.info(id); return id; } }new Controller().getContent(null); // error : Missing required argument.
用法同上,參數(shù)只有兩個(gè),和類裝飾器的前兩個(gè)一樣,常用來標(biāo)識(shí)屬性的特性。
function Column(target: any, name: string) { //把name存起來,這個(gè)column僅僅是標(biāo)識(shí)出來對(duì)應(yīng)數(shù)據(jù)庫中的列,常用在ORM框架中}class Table{ @Column name: string; }
另外還有屬性訪問器的裝飾器,和方法基本一樣,同樣的三個(gè)參數(shù),不過同個(gè)屬性的get
和set
只能有一個(gè)有,而且必須是先聲明的那個(gè)。
class User { private _name: string; @Enumerable(true) get name(){ return this._name; } set name(value: string) { this._name = value; } }
一個(gè)聲明可以添加多個(gè)裝飾器,所以會(huì)有個(gè)執(zhí)行先后順序。
首先從上到下執(zhí)行裝飾器函數(shù),然后再從下往上應(yīng)用帶括號(hào)的裝飾器返回的函數(shù)。
function Test1(){ console.info('eval test1'); return function(target: any, name: string, descriptor: PropertyDescriptor){ console.info('apply test1'); } }function Test2(){ console.info('eval test2'); return function(target: any, name: string, descriptor: PropertyDescriptor){ console.info('apply test2'); } }class User1{ @test1() @Test2() getName(){ } }
結(jié)果是:
eval test1eval test2 apply test2 apply test1
總之,裝飾器等于引入了天然的裝飾模式,給類,方法等添加額外功能。不過裝飾器目前還不算太穩(wěn)定,但是由于確實(shí)方便,已經(jīng)有成熟項(xiàng)目在使用了。
網(wǎng)頁題目:從C#到TypeScript-裝飾器
分享鏈接:http://m.newbst.com/article6/jocdig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)、App開發(fā)、全網(wǎng)營銷推廣、網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、網(wǎng)站排名
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)