當前位置:
首頁 > 最新 > 巧用匿名函數重構你的代碼

巧用匿名函數重構你的代碼

前言

國慶七天,大家的朋友圈攝影比賽如何啊?今日早讀文章由@Mapping分享。

正文從這開始~

匿名函數最早是LISP語言引入,後面發展為不僅是函數式語言所特有,在解釋型語言和編譯型語言中也越來越多地看到匿名函數的身影,它或許有個更潮的名字叫 lambda 表達式。

閉包多是用匿名函數實現,在匿名函數中引用了外部變數,那這個匿名函數就形成了閉包。由於閉包和匿名函數之間有著千絲萬縷的關係,所以經常會把兩者搞混淆。其實在 Js 中匿名函數、閉包、自執行函數、回調函數、箭頭函數,這些概念似乎相同,卻又不同,請讀者朋友自行了解。

匿名函數擁有可動態編程的執行過程。巧妙使用可以讓你的代碼簡約而不失優雅,靈活而不失約束。好了,正式切入本文的正題,巧用匿名函數重構代碼。按照重構的慣例,先指出代碼中的壞味(Bad Smell):

定義冗長的重複配置

條件多變的集合過濾

說一不二的方法調用

定義冗長的重複配置

在寫配置代碼時,經常會遇到大量重複的配置,如果要修改一些內容,所有的都要修改,著實很累,而且容易遺漏。比如:

{

html:`

Apple

Banana

Orange

`

}

這裡面有三個選項,三個選項的結構完全一樣,如果要給所有選項加一個 title,那你就要把這件事重複做三遍。

{

html:`

Apple

Banana

Orange

`

}

程序猿是個奇怪的群體,他們寧願做五件不同的事,也不願重複三次做同一件事。所以這怎麼能忍,把配置中不同的內容提取出來:

{

html:(function(fruits){

returnfruits.map(it=>`${it.title}`).join( );

}([

{name: apple ,title: Apple },

{name: banana ,title: Banana },

{name: orange ,title: Orange }

]))

}

這樣的修改對配置的調用方來說是完全透明的,但是對於配置的維護者來說,將結構和數據分離開,要改結構就改自執行方法體,要改數據就改傳入自執行方法的參數,可以大大減少犯錯的風險,又避免一些無腦的複製粘貼。

雖然在配置中寫代碼邏輯不是特別推薦的做法,但相對於代碼可維護性來說這不算啥了。

條件多變的集合過濾

集合過濾是個非常常見的需求,假設有個學生集合:

letstudents=[

{name: Lucy ,age:20,sex: female },

{name: LiLei ,age:21,sex: male },

{name: Jim ,age:18,sex: male }

]

現在要過濾出年齡 20 歲的同學:

functionfilterByAge(list,age){

letfiltered=[];

for(leti=;i

if(list[i].age===age){

filtered.push(list[i]);

}

}

returnfiltered;

}

又要過濾出姓名叫 LiLei 的同學:

functionfilterByName(list,name){

letfiltered=[];

for(leti=;i

if(list[i].name===name){

filtered.push(list[i]);

}

}

returnfiltered;

}

還要過濾出性別為男的同學:

functionfilterBySex(list,sex){

letfiltered=[];

for(leti=;i

if(list[i].sex===sex){

filtered.push(list[i]);

}

}

returnfiltered;

}

就在你覺得大功告成,可以站起彎伸腰的時刻,突然被一股強大的力量按回了座椅,幫我找出姓名以 「L」 開頭的童鞋。雖然你內心是 mmp~,但還能怎麼辦,寫啊,於是又吭哧吭哧加了如下方法:

functionfilterByNameStart(list,nameStart){

letfiltered=[];

for(leti=;i

if(list[i].name.indexOf(nameStart)===){

filtered.push(list[i]);

}

}

returnfiltered;

}

於是乎,這個調用方式:

filterByName(filterBySex(filterByAge(students,21), male ), LiLei );

就可以理解為找出年齡為 21 歲的男性 LiLei。好吧,可讀性還不算太差。

但是,不難看出以上 filterByAge、filterByNameStart 等這一系列方法中,除了過濾條件不同,其他邏輯完全一樣,造成了大量代碼的重複;並且沒有任何靈活性可言,調用方改需求,你就要加方法。

我們現在就使用匿名函數把不同的部分抽出去,讓調用方想怎麼過濾就過濾。filter 方法的主幹邏輯只關心當前的元素是不是要放入結果集合中,其他的判斷邏輯都交給匿名函數 fn 去做:

functionfilter(list,fn){

letfiltered=[];

for(leti=;i

if(fn(list[i],i)===true){

filtered.push(list[i]);

}

}

returnfiltered;

}

上面的例子會變成這種寫法:

filter(students,function(member){

returnmember.name=== LiLei &&member.age===21&&member.sex=== male ;

});

使用箭頭方法可以更簡潔:

filter(students,member=>member.name=== LiLei &&

member.age===21&&

member.sex=== male );

現在調用方再提一些變態的過濾方式,你可以回一個眼神,自己寫去。

說一不二的方法調用

假設有個 Api 介面,將傳入的數字翻倍並返回,這個介面支持單個和批量的方式。

傳入 5

執行成功返回

執行失敗返回

傳入 [2, 3]

執行成功返回 , ]}

執行失敗返回 , ]}

也就是單個輸入會按單個格式輸出,批量輸入會按批量格式輸出。三下五除二,實現了下面這個版本:

functionmultiple(inNum){

if(Array.isArray(inNum)){

// 處理批量情況

return{

status: success ,

data:inNum.map(it=>{

if(isNaN(parseFloat(it))){

return{

status: failed ,

error: The input is not a number

};

}

return{

status: success ,

data:it*2

}

})

};

}else{

// 處理單個情況

if(isNaN(parseFloat(inNum))){

return{

status: failed ,

error: The input is not a number

};

}

return{

status: success ,

data:inNum*2

};

}

}

這裡面單個和批量兩種方式除了輸入和輸出格式不同,其他邏輯完全一樣。如果要將乘 2 改成乘 3,兩個地方都要改。那看下怎麼使用匿名函數來避免兩處修改:

functionexecute(data,fn){

// 最小執行單元

letsingle=it=>{

try{

return{

status: success ,

data:fn(it)

};

}catch(e){

return{

status: failed ,

error:e.toString()

}

}

};

if(Array.isArray(data)){

return{

status: success ,

data:data.map(single)

}

}else{

returnsingle(data);

}

}

functionmultiple(inNum){

returnexecute(inNum,it=>{

if(isNaN(parseFloat(it))){

thrownewError( The input is not a number );

}

returnit*2;

});

}

現在 execute 方法只管輸入輸出的格式和錯誤處理,包攬了所有臟活累活;multiple 方法則只關心業務的具體實現,也不用關心輸入的是單個元素還是數組。如果要改乘 3,只要修改 multiple 方法最後一個 return。如此一來,execute 還可以被其他的 Api 方法復用,可謂一舉兩得。

總結

本文的目的只是拋磚引玉,代碼中可利用匿名函數重構的壞味還有很多,這種重構方式不只是適用於 Js 中。大家只要多思考、多動手,代碼質量一定會day day up~~

關於重構我還想多說一點,重構的過程應該是漸進的方式,當你改第一次的時候可能覺得還ok,第二次就要想下是不是有更好的方式來實現。如果修改對調用方透明那是最好了,實在不行讓調用方配合修改也是值得的,當然這其中還要權衡時間成本。

關於本文

作者:@Mapping

原文:https://iammapping.com/the-good-things-of-fn/


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 前端早讀課 的精彩文章:

跟隨 Google 工程師學習前端開發,是種怎樣的體驗?
小馬過河——Angular 學起來難嗎?
小馬過河——前後端是怎麼分家的?
【視頻】Machines must suffer
小馬過河——給萌新的 Angular 系列教程

TAG:前端早讀課 |