TS 裝飾器(2): 元數(shù)據(jù)

TS 裝飾器(2): 元數(shù)據(jù)

裝飾器函數(shù)中 ,我們可以拿到類眶明、方法艰毒、訪問符、屬性搜囱、參數(shù)的基本信息丑瞧,如它們的名稱柑土,描述符等。獲取更多信息就需要通過另外的方式來進(jìn)行:元數(shù)據(jù)绊汹。

1稽屏、什么是元數(shù)據(jù)?

元數(shù)據(jù):用來描述數(shù)據(jù)的數(shù)據(jù)西乖,在我們的程序中狐榔,對象、類等都是數(shù)據(jù)获雕,它們描述了某種數(shù)據(jù)薄腻。另外還有一種數(shù)據(jù),它可以用來描述 對象届案、類庵楷,這些用來描述數(shù)據(jù)的數(shù)據(jù)就是元數(shù)據(jù)

在編譯過程中產(chǎn)生的元數(shù)據(jù)是非常重要的信息楣颠,比如在 nestjs 框架中 DI 和 IOC 的實現(xiàn)久依賴了他們尽纽。

2、reflect-metadata

首先童漩,需要安裝 reflect-metadata弄贿。

2.1、定義元數(shù)據(jù)

我們可以給類矫膨、方法 等數(shù)據(jù)定義元數(shù)據(jù)差凹,元數(shù)據(jù)會被附加到指定的 類、方法等數(shù)據(jù)之上豆拨,但是又不會影響類直奋、方法本身的代碼能庆。

2.2施禾、使用語法

(1) 設(shè)置
Reflect.defineMetadata(metadataKey, metadataValue, target, propertyKey)

  • metadataKey:meta 數(shù)據(jù)的 key
  • metadataValue:meta 數(shù)據(jù)的 值
  • target:meta 數(shù)據(jù)附加的目標(biāo)
  • propertyKey(可選):對應(yīng)的 property key

(2) 獲取
Reflect.getMetadata(metadataKey, target, propertyKey)

import "reflect-metadata";

class A {
  public static method1() {}
  public method2() {}
}

let obj = new A();

Reflect.defineMetadata("key", 1, A);
Reflect.defineMetadata("key", 2, A, "method1");
Reflect.defineMetadata("key", 3, obj);
Reflect.defineMetadata("key", 4, A, "method2");

console.log(Reflect.getMetadata("key", A));
console.log(Reflect.getMetadata("key", A, "method1"));
console.log(Reflect.getMetadata("key", obj));
console.log(Reflect.getMetadata("key", obj, "method2"));

2.3、裝飾器簡化操作

  • 通過 Reflect.defineMetadata 方法調(diào)用來添加元數(shù)據(jù)
  • 通過 @Reflect.metadata 裝飾器來添加元數(shù)據(jù)
import "reflect-metadata";

@Reflect.metadata("key", 1)
class A {
  @Reflect.metadata("key", 2)
  public static method1() {}

  @Reflect.metadata("key", 4)
  public method2() {}
}

let obj = new A();

console.log(Reflect.getMetadata("key", A));
console.log(Reflect.getMetadata("key", A, "method1"));
console.log(Reflect.getMetadata("key", obj));
console.log(Reflect.getMetadata("key", obj, "method2"));

3搁胆、使用 emitDecoratorMetadata

如何知道一個方法中有多少個參數(shù)弥搞,每個參數(shù)的類型是什么呢?tsconfig.json 中有一個配置 emitDecoratorMetadata渠旁,開啟該特性攀例,typescript 會在編譯之后自動給類、方法顾腊、訪問符粤铭、屬性、參數(shù)添加如下幾個元數(shù)據(jù):

  • design:type:被裝飾目標(biāo)的類型
    • 裝飾器作用于成員屬性:屬性的標(biāo)注類型
    • 裝飾器作用于成員方法:Function 類型
  • design:paramtypes: 被裝飾目標(biāo)的參數(shù)類型
    • 裝飾器作用于成員方法:方法形參列表的標(biāo)注類型
    • 裝飾器作用于類:構(gòu)造函數(shù)形參列表的標(biāo)注類型
  • design:returntype
    • 成員方法:函數(shù)返回值的標(biāo)注類型

3.1杂靶、方法裝飾器實驗

源碼:

function f() {
  return function (target: any, name: string, descriptor: PropertyDescriptor) {
    console.log(descriptor.value.length);
  };
}

class B {
  name: string;
  constructor(a: string) {
    this.name = a;
  }
  @f()
  method(a: string, b: string): string {
    return "a";
  }
}

產(chǎn)物:

// 太長了梆惯,隱藏實現(xiàn)
var __decorate = function () {}

var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};

function f() {
    return function (target, name, descriptor) {
        console.log(descriptor.value.length);
    };
}
var B = /** @class */ (function () {
    function B(a) {
        this.name = a;
    }
    B.prototype.method = function (a, b) {
        return "a";
    };
    __decorate([
        f(),
        __metadata("design:type", Function),
        __metadata("design:paramtypes", [String, String]),
        __metadata("design:returntype", String)
    ], B.prototype, "method", null);
    return B;
}());

3.2酱鸭、類裝飾器實驗

@testable
class MyTestableClass {
  constructor (name: string, age: number) {}
}

function testable(target: Function) {
  (target as any).isTestable = true;
}

(MyTestableClass as any).isTestable // true

產(chǎn)物:

var MyTestableClass = /** @class */ (function () {
    function MyTestableClass(name, age) {
    }
    MyTestableClass = __decorate([
        testable,
        __metadata("design:paramtypes", [String, Number])
    ], MyTestableClass);
    return MyTestableClass;
}());
function testable(target) {
    target.isTestable = true;
}
MyTestableClass.isTestable; // true
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市垛吗,隨后出現(xiàn)的幾起案子凹髓,更是在濱河造成了極大的恐慌,老刑警劉巖怯屉,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蔚舀,死亡現(xiàn)場離奇詭異,居然都是意外死亡锨络,警方通過查閱死者的電腦和手機(jī)赌躺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來羡儿,“玉大人寿谴,你說我怎么就攤上這事∈埽” “怎么了讶泰?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拂到。 經(jīng)常有香客問我痪署,道長,這世上最難降的妖魔是什么兄旬? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任狼犯,我火速辦了婚禮,結(jié)果婚禮上领铐,老公的妹妹穿的比我還像新娘悯森。我一直安慰自己,他們只是感情好绪撵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布瓢姻。 她就那樣靜靜地躺著,像睡著了一般音诈。 火紅的嫁衣襯著肌膚如雪幻碱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天细溅,我揣著相機(jī)與錄音褥傍,去河邊找鬼。 笑死喇聊,一個胖子當(dāng)著我的面吹牛恍风,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼朋贬,長吁一口氣:“原來是場噩夢啊……” “哼鸥咖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起兄世,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤啼辣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后御滩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸥拧,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年削解,在試婚紗的時候發(fā)現(xiàn)自己被綠了富弦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡氛驮,死狀恐怖腕柜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情矫废,我是刑警寧澤盏缤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站蓖扑,受9級特大地震影響唉铜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜律杠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一潭流、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧柜去,春花似錦灰嫉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔓罚,卻和暖如春椿肩,著一層夾襖步出監(jiān)牢的瞬間瞻颂,已是汗流浹背豺谈。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贡这,地道東北人茬末。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親丽惭。 傳聞我的和親對象是個殘疾皇子击奶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容