Decorator 修飾器

修飾器

修飾器是 ES7 提出的一個提案,用來修改類的行為。目前需要 babel 才可以使用子姜。它最大的特點是:可以在編譯期運行代碼巨柒!其本質也就是在編譯器執(zhí)行的函數(shù)。其執(zhí)行格式如下:

@decorator    //decorator 是修飾器名,即函數(shù)名
class A{}
//相當于
class A{}
A = decorator(A) || A;

修飾器函數(shù)接受3個參數(shù),依次是目標函數(shù)、屬性名(可忽略)哗伯、該屬性的描述對象(可忽略)。

function test(target){
  target.isTestable = true;               //利用修飾器給類添加靜態(tài)屬性
  target.prototype.isTestable = true;     //利用修飾器給類添加動態(tài)屬性
}

@test
class A{}

console.log(A.isTestable);       //true
console.log(new A().isTestable);   //true

例如之前的 mixin 可以用修飾器實現(xiàn)一個簡單的版本:

function mixins(...list){
  return function(target){
    Object.assign(target.prototype, ...list);
  }
}
var Foo = {
  foo(){console.log("foo");}
};
@mixins(Foo)
class Cla{}
let obj = new Cla();
obj.foo();     //"foo"

修飾器不僅僅可以修飾類篷角,還可以修飾類的屬性和方法:

function readonly(target, name, descriptor){
  descriptor.writable = false;
  return descriptor;
}

class Person{
  constructor(name, age, tel){
    this.name = name;
    this.id = id;
  }
  @readonly
  id(){return this.id};
}

當然也可以同時調用2個修飾器:

function readonly(target, name, descriptor){
  descriptor.writable = false;
  return descriptor;
}
function nonenumerable(target, name, descriptor){
  descriptor.enumerable = false;
  return descriptor;
}

class Person{
  constructor(name, age, tel){
    this.name = name;
    this.id = id;
  }
  @readonly
  @nonenumerable
  id(){return this.id};
}

使用修飾器應該注意:雖然類本質是個函數(shù)焊刹,但修飾器不能用于函數(shù),因為函數(shù)具有聲明提升恳蹲。

core-decroators.js

這是個三方模塊虐块,使用import {function Namelist} from 'core-decroators';引入。它提供了幾個常見的修飾器:

  • @autobind
    是對象中的 this 始終綁定原始對象:
class Person{
  @autobind
  whoami(){
    return this;
  }
}
let person = new Person();
let getPerson = person.getPerson;

getPerson() === person;    //true
  • @readonly
    使得屬性方法只讀
class Person{
  @readonly
  id = gen();     //gen 是一個計數(shù)器
}
var p = new Person()
p.id = 123;   //Cannot assign to read only property 'id' of [object Object]
  • @override
    檢查子類方法是否正確的覆蓋了父類的同名方法嘉蕾,如果不正確會報錯
class Person{
  work(){console.log("I am working");}
}
class Coder extends Person{
  @override
  work(){console.log("I am coding");}   //如果不正確會在這里報錯
}
  • @deprecate(也作: @deprecated)
    在控制臺顯示一條 warning贺奠,表示該方法不久后將被廢除,接受一個可選的參數(shù)作為警告內(nèi)容, 接受第二個參數(shù)(對象)表示更多信息
class Person{
  @deprecate
  facepalm(){}

  @deprecate('We stopped facepalming')
  facepalmHard(){}

  @deprecate('We stopped facepalming', {url:'http://balabala.com'})
  facepalmHarder(){}
}
  • @suppressWarnings
    抑制 deprecate 修飾器導致調用 console.warn(), 但異步代碼發(fā)出的除外错忱。
class Person{
  @deprecate
  facepalm(){}

  @supressWarnings
  facepalmWithoutWarning(){
    this.facepalm();
  }
}
let p = new Person();
p.facepalm();    //控制臺顯示警告
p.facepalmWithoutWarning();    //沒有警告

其它第三方修飾器

此外還有一些庫提供一些其他功能儡率,比如 Postal.js(Github)中的 @publish, 可以在函數(shù)調用時發(fā)布一個事件:

import publish from "../to/decorators/publish";

class FooComponent{
  @publish("foo.some.message", "component")
  someMethod(){}

  @publish("foo.some.other", "")
  anotherMethod(){}
}

再比如 Trait(Github), 和 mixin 功能類似,提供了更強大的功能:防止同名沖突以清,排除混入某些方法儿普,為混入方法起別名等

import {traits} from 'traits-decorator'

class TFoo{
  foo(){console.log("foo1")}
}
class TBar{
  bar(){console.log("bar")}
  foo(){console.log("foo2")}
}

@traits(TFoo, TBar)       //會報錯,因為這兩個類中有同名方法
class MyClass{}

let obj = new MyClass();
//如果沒有第八行的同名方法掷倔,輸出如下
obj.foo();   //"foo1"
obj.bar();   //"bar"

但是我們可以修改上面第11行排除這個 foo眉孩,讓它可以被覆蓋:

@traits(TFoo, TBar::excludes('foo'))
class MyClass{}

也可重命名同名方法:

@traits(TFoo, TBar::alias(foo:'aliasFoo'))
class MyClass{}

當然綁定運算符可以鏈式調用:

//假設還有個同名的 baz 方法
@traits(TFoo, TBar::excludes('foo')::alias(baz:'aliasBaz'))
class MyClass{}

//另一種寫法
@traits(TFoo, TBar::as({excludes: ['foo'], alias: {baz:'aliasBaz'}}))
class MyClass{}
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子浪汪,更是在濱河造成了極大的恐慌巴柿,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件死遭,死亡現(xiàn)場離奇詭異广恢,居然都是意外死亡,警方通過查閱死者的電腦和手機殃姓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門袁波,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓦阐,“玉大人蜗侈,你說我怎么就攤上這事∷” “怎么了踏幻?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長戳杀。 經(jīng)常有香客問我该面,道長,這世上最難降的妖魔是什么信卡? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任隔缀,我火速辦了婚禮,結果婚禮上傍菇,老公的妹妹穿的比我還像新娘猾瘸。我一直安慰自己,他們只是感情好丢习,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布牵触。 她就那樣靜靜地躺著,像睡著了一般咐低。 火紅的嫁衣襯著肌膚如雪揽思。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天见擦,我揣著相機與錄音钉汗,去河邊找鬼。 笑死鲤屡,一個胖子當著我的面吹牛损痰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播执俩,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼徐钠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了役首?” 一聲冷哼從身側響起尝丐,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤显拜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爹袁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體远荠,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年失息,在試婚紗的時候發(fā)現(xiàn)自己被綠了譬淳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡盹兢,死狀恐怖邻梆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绎秒,我是刑警寧澤浦妄,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站见芹,受9級特大地震影響剂娄,放射性物質發(fā)生泄漏。R本人自食惡果不足惜玄呛,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一阅懦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧徘铝,春花似錦耳胎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怠缸,卻和暖如春诗轻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揭北。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工扳炬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搔体。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓恨樟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疚俱。 傳聞我的和親對象是個殘疾皇子劝术,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

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