Javascript裝飾器的妙用

最近新開了一個Node項目助币,采用TypeScript來開發(fā),在數(shù)據(jù)庫及路由管理方面用了不少的裝飾器燕雁,發(fā)覺這的確是一個好東西诞丽。
裝飾器是一個還處于草案中的特性,目前木有直接支持該語法的環(huán)境拐格,但是可以通過 babel 之類的進(jìn)行轉(zhuǎn)換為舊語法來實現(xiàn)效果僧免,所以在TypeScript中,可以放心的使用@Decorator捏浊。

什么是裝飾器
裝飾器是對類懂衩、函數(shù)、屬性之類的一種裝飾金踪,可以針對其添加一些額外的行為浊洞。
通俗的理解可以認(rèn)為就是在原有代碼外層包裝了一層處理邏輯。
個人認(rèn)為裝飾器是一種解決方案热康,而并非是狹義的@Decorator沛申,后者僅僅是一個語法糖罷了。

裝飾器在身邊的例子隨處可見姐军,一個簡單的例子铁材,水龍頭上邊的起泡器就是一個裝飾器,在裝上以后就會把空氣混入水流中奕锌,摻雜很多泡泡在水里著觉。
但是起泡器安裝與否對水龍頭本身并沒有什么影響,即使拆掉起泡器惊暴,也會照樣工作饼丘,水龍頭的作用在于閥門的控制,至于水中摻不摻雜氣泡則不是水龍頭需要關(guān)心的辽话。

所以肄鸽,對于裝飾器卫病,可以簡單地理解為是非侵入式的行為修改。

為什么要用裝飾器
可能有些時候典徘,我們會對傳入?yún)?shù)的類型判斷蟀苛、對返回值的排序、過濾逮诲,對函數(shù)添加節(jié)流帜平、防抖或其他的功能性代碼,基于多個類的繼承梅鹦,各種各樣的與函數(shù)邏輯本身無關(guān)的裆甩、重復(fù)性的代碼。

函數(shù)中的作用
可以想像一下齐唆,我們有一個工具類嗤栓,提供了一個獲取數(shù)據(jù)的函數(shù):

class Model1 {
getData() {
// 此處省略獲取數(shù)據(jù)的邏輯
return [{
id: 1,
name: 'Niko'
}, {
id: 2,
name: 'Bellic'
}]
}
}

console.log(new Model1().getData()) // [ { id: 1, name: 'Niko'}, { id: 2, name: 'Bellic' } ]
console.log(Model1.prototype.getData()) // [ { id: 1, name: 'Niko'}, { id: 2, name: 'Bellic' } ]
復(fù)制代碼
現(xiàn)在我們想要添加一個功能,記錄該函數(shù)執(zhí)行的耗時蝶念。
因為這個函數(shù)被很多人使用抛腕,在調(diào)用方添加耗時統(tǒng)計邏輯是不可取的,所以我們要在Model1中進(jìn)行修改:

class Model1 {
getData() {

  • let start = new Date().valueOf()
  • try {
    // 此處省略獲取數(shù)據(jù)的邏輯
    return [{
    id: 1,
    name: 'Niko'
    }, {
    id: 2,
    name: 'Bellic'
    }]
  • } finally {
  • let end = new Date().valueOf()
    
  • console.log(`start: ${start} end: ${end} consume: ${end - start}`)
    
  • }
    }
    }

// start: XXX end: XXX consume: XXX
console.log(new Model1().getData()) // [ { id: 1, name: 'Niko'}, { id: 2, name: 'Bellic' } ]
// start: XXX end: XXX consume: XXX
console.log(Model1.prototype.getData()) // [ { id: 1, name: 'Niko'}, { id: 2, name: 'Bellic' } ]
復(fù)制代碼
這樣在調(diào)用方法后我們就可以在控制臺看到耗時的輸出了媒殉。
但是這樣直接修改原函數(shù)代碼有以下幾個問題:

統(tǒng)計耗時的相關(guān)代碼與函數(shù)本身邏輯并無一點(diǎn)關(guān)系担敌,影響到了對原函數(shù)本身的理解,對函數(shù)結(jié)構(gòu)造成了破壞性的修改
如果后期還有更多類似的函數(shù)需要添加統(tǒng)計耗時的代碼廷蓉,在每個函數(shù)中都添加這樣的代碼顯然是低效的全封,維護(hù)成本太高
所以,為了讓統(tǒng)計耗時的邏輯變得更加靈活桃犬,我們將創(chuàng)建一個新的工具函數(shù)刹悴,用來包裝需要設(shè)置統(tǒng)計耗時的函數(shù)。
通過將Class與目標(biāo)函數(shù)的name傳遞到函數(shù)中攒暇,實現(xiàn)了通用的耗時統(tǒng)計:

function wrap(Model, key) {
// 獲取Class對應(yīng)的原型
let target = Model.prototype

// 獲取函數(shù)對應(yīng)的描述符
let descriptor = Object.getOwnPropertyDescriptor(target, key)

// 生成新的函數(shù)土匀,添加耗時統(tǒng)計邏輯
let log = function (...arg) {
let start = new Date().valueOf()
try {
return descriptor.value.apply(this, arg) // 調(diào)用之前的函數(shù)
} finally {
let end = new Date().valueOf()
console.log(start: ${start} end: ${end} consume: ${end - start})
}
}

// 將修改后的函數(shù)重新定義到原型鏈上
Object.defineProperty(target, key, {
...descriptor,
value: log // 覆蓋描述符重的value
})
}

wrap(Model1, 'getData')
wrap(Model2, 'getData')

// start: XXX end: XXX consume: XXX
console.log(new Model1().getData()) // [ { id: 1, name: 'Niko'}, { id: 2, name: 'Bellic' } ]
// start: XXX end: XXX consume: XXX
console.log(Model2.prototype.getData()) // [ { id: 1, name: 'Niko'}, { id: 2, name: 'Bellic' } ]
復(fù)制代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市形用,隨后出現(xiàn)的幾起案子就轧,更是在濱河造成了極大的恐慌,老刑警劉巖田度,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件妒御,死亡現(xiàn)場離奇詭異,居然都是意外死亡镇饺,警方通過查閱死者的電腦和手機(jī)乎莉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惋啃,你說我怎么就攤上這事哼鬓。” “怎么了肥橙?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵魄宏,是天一觀的道長。 經(jīng)常有香客問我存筏,道長,這世上最難降的妖魔是什么味榛? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任椭坚,我火速辦了婚禮,結(jié)果婚禮上搏色,老公的妹妹穿的比我還像新娘善茎。我一直安慰自己,他們只是感情好频轿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布垂涯。 她就那樣靜靜地躺著,像睡著了一般航邢。 火紅的嫁衣襯著肌膚如雪耕赘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天膳殷,我揣著相機(jī)與錄音操骡,去河邊找鬼。 笑死赚窃,一個胖子當(dāng)著我的面吹牛册招,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播勒极,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼是掰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了辱匿?” 一聲冷哼從身側(cè)響起键痛,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎掀鹅,沒想到半個月后散休,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡乐尊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年戚丸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡限府,死狀恐怖夺颤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胁勺,我是刑警寧澤世澜,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站署穗,受9級特大地震影響寥裂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜案疲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一封恰、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧褐啡,春花似錦诺舔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至懂盐,卻和暖如春褥赊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背允粤。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工崭倘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人类垫。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓司光,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悉患。 傳聞我的和親對象是個殘疾皇子残家,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

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