真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

從C#到TypeScript-裝飾器

從C#到TypeScript - 裝飾器

在C#里面如果想要不直接修改類或方法,但給類或方法添加一些額外的信息或功能,可以想到用Attribute,這是一個十分方便的功能裝飾器。
用TypeScript同樣也可以利用裝飾器來給類、函數(shù)、屬性以及參數(shù)添加附加功能,裝飾器是ES7的一個提案,在TypeScript里已經(jīng)有實現(xiàn)可用,不過需要在tsconfig.json里啟用experimentalDecorators。

創(chuàng)新互聯(lián)是專業(yè)的射洪網(wǎng)站建設(shè)公司,射洪接單;提供成都網(wǎng)站建設(shè)、網(wǎng)站制作,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進行射洪網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

"compilerOptions": {
    ..., // other options
    "experimentalDecorators": true}

裝飾器介紹

TypeScript中裝飾器可以應(yīng)用到類、方法、屬性及函數(shù)參數(shù)上,而且可以同時應(yīng)用多個。
裝飾器的寫法是@name(),()可以不要,也可以在里面寫一些參數(shù)。

@Testable
@Log('controller')class Controller{

    @GET
    getContent(@QueryParam arg: string): string{        return '';
    }
}

裝飾器的實現(xiàn)

裝飾器根據(jù)實現(xiàn)可以分兩種:
一種是不帶括號,和屬性一樣,如@Testable。

function Testable(target: Function) { // 類、方法、屬性、方法參數(shù)的參數(shù)各不相同
    //這里可以記錄一些信息到target,或者針對target做一些處理,如seal}

另外一種是帶括號的,和函數(shù)一樣,如@Log('controller'),實現(xiàn)函數(shù)里的參數(shù)就是括號里的參數(shù),而且需要返回一個function。

function Log(name: string) { // name就是傳進來的參數(shù)'controller'
    return function(target: Function) { // 類、方法、屬性、方法參數(shù)的參數(shù)各不相同
        // 這里可以根據(jù)name和target來做一些處理
    }
}

類裝飾器

上面的(target: Function)其實就是類的裝飾器參數(shù),指向的是類的構(gòu)造函數(shù),如果想給類加一個簡單的seal功能,可以這樣做:

function sealed(target: Function) {    Object.seal(target);    Object.seal(target.prototype);
}

@sealedclass Test{
    
}

Test.prototype.test = ''; // 運行時出錯,不能添加

上面的sealed就是類的裝飾器,target指構(gòu)造函數(shù),類裝飾器就這么一個參數(shù)。

方法裝飾器

方法裝飾器的使用方法和類裝飾器類似,只是參數(shù)不一樣,方法裝飾器有三個參數(shù):

  1. 如果裝飾的是靜態(tài)方法,則是類的構(gòu)造函數(shù),如果是實例方法則是類的原型。

  2. 方法的名字。

  3. 方法的PropertyDescriptor。
    PropertyDescriptor即屬性描述符,有
    configurable 是否可以配置,如動態(tài)添加刪除函數(shù)屬性之類
    writable 是否可寫,可以用來設(shè)置只讀屬性
    enumerable 是否可枚舉,即是否能在for...in中能枚舉到
    value 對象或?qū)傩缘闹?/p>

有了這些參數(shù)就可以很好的給方法添加一些功能,比如下面實現(xiàn)類型WebApi里的Get的路由:

const Router = Symbol(); // 唯一key,用來存裝飾器的信息function GET(path?: string) { // GET帶了個可選參數(shù)
    return (target: any, name: string) => setMethodDecorator(target, name, 'GET', path);
}//把method和path存起來,路由查找的時候就可以用了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ù)裝飾器

方法參數(shù)同樣可以有裝飾器,同樣有三個參數(shù),前兩個參數(shù)和方法的一致,最后一個參數(shù)是所裝飾的參數(shù)的位置。
能過參數(shù)裝飾器可以給方法動態(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ù)只有兩個,和類裝飾器的前兩個一樣,常用來標(biāo)識屬性的特性。

function Column(target: any, name: string) {    //把name存起來,這個column僅僅是標(biāo)識出來對應(yīng)數(shù)據(jù)庫中的列,常用在ORM框架中}class Table{

    @Column  
    name: string;
}

另外還有屬性訪問器的裝飾器,和方法基本一樣,同樣的三個參數(shù),不過同個屬性的getset只能有一個有,而且必須是先聲明的那個。

class User {    private _name: string;

    @Enumerable(true)    get name(){        return this._name;
    }    set name(value: string) {        this._name = value;
    }
}

多個裝飾器的執(zhí)行順序

一個聲明可以添加多個裝飾器,所以會有個執(zhí)行先后順序。
首先從上到下執(zhí)行裝飾器函數(shù),然后再從下往上應(yīng)用帶括號的裝飾器返回的函數(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)定,但是由于確實方便,已經(jīng)有成熟項目在使用了。


本文標(biāo)題:從C#到TypeScript-裝飾器
標(biāo)題URL:http://weahome.cn/article/jocdig.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部