什么是裝飾器模式
ES6/ES7中的裝飾器模式簡(jiǎn)而言之就是對(duì)現(xiàn)有類進(jìn)行一個(gè)包裝徒蟆,不通過子類或者改變其內(nèi)部結(jié)構(gòu)的方式為其擴(kuò)展功能鬼贱。
通俗的說,就是將現(xiàn)有的類變得更加“華麗”硕勿,比如禮物可以直接送鄙早,但是加上禮品盒更美觀弄慰,手機(jī)可以直接用,但是加上鋼化膜更耐摔蝶锋。以“吃雞”游戲?yàn)槔?8k本身就具有狙擊功能陆爽。安裝狙消音可以槍具有消音功能,8倍鏡可以擴(kuò)大視野范圍扳缕,槍托可以增加強(qiáng)的穩(wěn)定性慌闭,這些都沒有改變?cè)械?8k可以狙擊的功能,只是讓它的屬性變得更強(qiáng)躯舔。
裝飾器的行為可以理解為如下:
@decorator
class A{ }
//? 等同于
class A = { }
A = decorator(A) || A;
裝飾器的本質(zhì)就是一個(gè)函數(shù)驴剔,它具有三個(gè)參數(shù)target、key粥庄、descriptor丧失。target是裝飾的對(duì)象,key是裝飾對(duì)象的具體屬性惜互,也就是修飾器緊跟其后的屬性名字布讹。descriptor是該屬性的描述對(duì)象,自帶configurable训堆、value描验、enumerable、writable坑鱼、__proto__屬性膘流。
裝飾類
function decorator(target) {
????target.age = 20; // 為類添加靜態(tài)屬性
????target.prototype.grade = 3; // 為類添加實(shí)例屬性
}
@decorator
class Student{ }
const student = new Student();
console.log(student.age);? //20
console.log(student.grade)? //3
上述方法中,本身Student類沒有任何屬性,因?yàn)樽⑷胙b飾器之后呼股,Student擁有了靜態(tài)屬性age和實(shí)例屬性grade耕魄。裝飾器除了可以裝飾類,還可以裝飾類的方法彭谁。
裝飾類的方法
class Math {
????@log
????add(a, b) { return a + b; }
}
function log(target, name, descriptor) {
????var oldValue = descriptor.value;
????descriptor.value = function() {
????????console.log(`Calling ${name} with`, arguments);
????????return oldValue.apply(this, arguments);
????};
????return descriptor;
}
const math = new Math();
add(2, 4);
//calling add with [2屎开,4]
@log是一個(gè)打印裝飾器,裝飾了Math類的add函數(shù)马靠,通過修改屬性描述對(duì)象的值descriptor.value實(shí)現(xiàn)打印功能。裝飾后蔼两,每次調(diào)用add函數(shù)都會(huì)打印調(diào)用時(shí)的相關(guān)日志甩鳄。
注意:如果同一個(gè)方法有多個(gè)修飾器,會(huì)像剝洋蔥一樣额划,先從外到內(nèi)進(jìn)入妙啃,然后由內(nèi)向外執(zhí)行。
裝飾器在react中的應(yīng)用
@connnet裝飾器
react-redux的常規(guī)使用俊戳,一般需要先定義UI組件后揖赴,再使用connect函數(shù)將UI組件變?yōu)槿萜鹘M件導(dǎo)出
class UIComponent extends React.Component {? }
const ContainerComponent = connect( mapStateToProps , mapDispatchToProps )( UIComponent );
export default ContainerComponent;
使用裝飾器后,無需再定義容器組件
@connect( mapStateToProps? , mapDispatchToProps )
class UIComponent extends React.Component {? }
export default UIComponent;
定制高階組件
有時(shí)業(yè)務(wù)中需要定義自己的高階組件抑胎,實(shí)現(xiàn)代碼的復(fù)用燥滑。比如在業(yè)務(wù)開發(fā)中,每個(gè)頁面的預(yù)加載功能可以作為一個(gè)裝飾器阿逃。