其實(shí)說起來不讓寫工作總結(jié),但是實(shí)際上這還是一篇工作總結(jié)煤裙。掩完。。硼砰。
ok且蓬!切入正題,我們來討論一下如何簡化代碼题翰,其實(shí)這也都是最近在實(shí)際開發(fā)時(shí)的體會(huì)恶阴,而且本身我不是很擅長這一點(diǎn)。但是最近因?yàn)閷懙拇a邏輯略微繁復(fù)豹障,而且本身需要兼容的情況比較多冯事,加上繁復(fù)的現(xiàn)實(shí)條件(比如編譯環(huán)境,比如設(shè)備性能血公,比如運(yùn)行平臺(tái)等等)的干擾昵仅,導(dǎo)致很多時(shí)候展示出來效果不是很好,所以就在本來邏輯較為復(fù)雜的代碼上又添加了許多判斷狀態(tài)的代碼累魔,這就讓代碼的可讀性摔笤,可維護(hù)性,健壯性都下降了很多垦写,代碼的耦合度直線上升吕世,當(dāng)具體的邏輯和實(shí)際的需求有任何一點(diǎn)點(diǎn)的變化,就會(huì)產(chǎn)生多米諾骨牌效果梯投,不但改的時(shí)候很難理清添加了多層嵌套與判斷的代碼命辖,在修改之后還可能牽連另外的功能產(chǎn)生意想不到的變化况毅。所以,為了不讓同志們屌我尔艇,我還是對(duì)代碼進(jìn)行了一定程度上的改造尔许。
其實(shí)感覺上面還是在說廢話。漓帚。。午磁。當(dāng)然啦尝抖,簡單闡述一下博客的靈感來源嘛!~
其實(shí)很久以前看過類似的文章迅皇,專門介紹了很多提高代碼可讀性以及運(yùn)行速度的方法昧辽,具體的文章題目與鏈接我忘記了,應(yīng)該可以搜索“如何簡化代碼”找到登颓。文章中的主要思想大致就是分離搅荞,合并:將該分離的一些變量,不需要強(qiáng)行的使用一個(gè)變量將內(nèi)容統(tǒng)一框咙,該添加變量的時(shí)候就添加新的變量咕痛;而合并就是將能統(tǒng)一判斷的內(nèi)容提升到高層倍权,而不需要逐個(gè)寫在每一個(gè)判斷體或者循環(huán)體中爱沟,這樣既能簡化函數(shù),又可以提升運(yùn)行速度准潭。
我也是以這樣的思想為核心進(jìn)行重構(gòu)代碼的者铜,結(jié)合實(shí)際情況腔丧,主要有以下幾點(diǎn)想法吧:
1. if判斷體不要寫的太長。if寫多長其實(shí)本身并不影響邏輯作烟,但是卻很影響可讀性愉粤。if本身是添加嵌套的,當(dāng)寫的很長了之后拿撩,會(huì)出現(xiàn)很現(xiàn)實(shí)的問題--------找不到else if與else的對(duì)應(yīng)衣厘。當(dāng)在if內(nèi)部再嵌套了if之后,寫的時(shí)候或許還比較清楚压恒,但是當(dāng)寫完之后需要讀或者改的時(shí)候头滔,在看到一長串的if之后突然出來一個(gè)else,當(dāng)然會(huì)產(chǎn)生這個(gè)else究竟對(duì)應(yīng)誰的疑問吧涎显!
2. 不要怕繁瑣坤检,多聲明函數(shù)。上面說了期吓,if不能寫太長早歇,那么如果if的邏輯真的很多那么該怎么辦呢倾芝?
? ? ? 首先,你應(yīng)該確定箭跳,if的邏輯真的很多晨另,很多的邏輯其實(shí)是可以提升到判斷體之外去做的,比如在不同的判斷內(nèi)容后谱姓,都需要將某一個(gè)計(jì)數(shù)器+1借尿,那么這個(gè)計(jì)數(shù)器當(dāng)然就可以放在判斷的外面整體去做,而不是放在內(nèi)部一個(gè)一個(gè)去做屉来。這一步檢查需要仔細(xì)一些路翻,因?yàn)楹芏鄡?nèi)容可能在編碼的過程中寫在了判斷體的中間部位,而實(shí)際上有一些聲明或者值的改變完全是可以放在開頭和結(jié)尾的茄靠,這些都可以從判斷體中提出茂契。
????其次就是要抽離函數(shù)了,這一步最簡單粗暴的方法就是將函數(shù)體的內(nèi)容復(fù)制粘貼慨绳,放到聲明的另一個(gè)額外的函數(shù)之中掉冶。這一步在初學(xué)者看來可能有一些多此一舉,但是在實(shí)際開發(fā)過程中脐雪,基于工程化厌小,模塊化的要求,這樣寫代碼可以很直觀的了解到哪一部分功能是什么战秋,也提升了代碼的可讀性召锈,在修改代碼的時(shí)候也可以很明確的根據(jù)bug的表現(xiàn)定位到具體相關(guān)的位置。
????最后一步获询,我們要再次確定涨岁,這些冗長的邏輯真的是必須的。這一部分是什么意思呢吉嚣?因?yàn)樵趦蓚€(gè)不同的判斷體之中梢薪,我們往往判斷的只是一個(gè)或者兩個(gè)不同的條件,而需要調(diào)整的變量尝哆,對(duì)象秉撇,屬性等等一般都是同一種或者同一類,在整理邏輯之后我們經(jīng)城镄梗可以發(fā)現(xiàn)琐馆,調(diào)整的內(nèi)容完全可以通過傳入一些變量進(jìn)行改變,這樣就可以把一些類似的邏輯又抽成一個(gè)額外的函數(shù)恒序,達(dá)到了簡化代碼的目的瘦麸。
3.既然說到了函數(shù)那么就想聊聊回調(diào)函數(shù)了。為什么想聊一聊這個(gè)內(nèi)容呢歧胁?因?yàn)檫@周自己在工作過程中寫到了一個(gè)回調(diào)函數(shù)滋饲,雖然的確很難懂厉碟,但是這種函數(shù)式的操作真的很cooool~,而且功能極其強(qiáng)大屠缭。
? ? 首先箍鼓,我們需要簡單了解一下回調(diào)函數(shù)是什么。
百度百科:回調(diào)函數(shù)就是一個(gè)通過函數(shù)指針調(diào)用的函數(shù)呵曹。 如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù)款咖,當(dāng)這個(gè)指針被用來調(diào)用其所指向的函數(shù)時(shí),我們就說這是回調(diào)函數(shù)奄喂。?回調(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用铐殃,而是在特定的事件或條件發(fā)生時(shí)由另外的一方調(diào)用的,用于對(duì)該事件或條件進(jìn)行響應(yīng)砍聊。
? 很多語言都有回調(diào)函數(shù)背稼,其在語言的底層實(shí)現(xiàn)的方式雖然不同贰军,但是其功能都是類似的玻蝌,而且從方式上來看,都是將函數(shù)作為參數(shù)傳入到另一個(gè)函數(shù)之中词疼。
function fn(arg1, arg2, callback){
? ? var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
? ? callback(num); //傳遞結(jié)果
}
fn(10, 20, function(num){
? console.log("Callback called! Num: " + num);
}); //結(jié)果為10和20之間的隨機(jī)數(shù)
? 我們上網(wǎng)去搜回調(diào)函數(shù)俯树,給出的最簡單的示例一般就是這樣,看到這樣的示例我一般會(huì)先通讀一下代碼贰盗,理解它的涵義许饿。這個(gè)示例并不難理解,fn是一個(gè)聲明的函數(shù)舵盈,callback是一個(gè)函數(shù)類型的參數(shù)陋率,它將在函數(shù)中被調(diào)用,但是它的實(shí)現(xiàn)會(huì)在它調(diào)用的時(shí)候才會(huì)確定秽晚。但是理解之后我就隨之冒出一個(gè)問題瓦糟,這樣寫是多此一舉把?我為什么不直接在函數(shù)fn中寫一個(gè)console就好了赴蝇,而用這樣復(fù)雜的回調(diào)函數(shù)形式寫出這么冗雜難讀的代碼呢菩浙?
????這里就得思考一下回調(diào)函數(shù)的意義了,有人曾解釋過回調(diào)函數(shù)句伶,說之所以使用回調(diào)函數(shù)劲蜻,是因?yàn)樵俾暶骰卣{(diào)的時(shí)候,使用者自己都不知道回調(diào)函數(shù)要干什么考余。我覺得這種解釋有一定道理先嬉,但是不夠準(zhǔn)確。如果楚堤,我完全不知道某個(gè)函數(shù)要干嘛坝初,那我為什么要這個(gè)函數(shù)寫在這里呢浸剩?所以說,這個(gè)概念本身很模糊鳄袍,以至于我寫了多少年也沒有手動(dòng)原生寫過一個(gè)回調(diào)函數(shù)绢要。直到上周我在實(shí)際開發(fā)中突然靈光一閃使用到了這個(gè)久違的功能,才大致明白了回調(diào)函數(shù)存在的意義拗小,以下基本是我想到的可以使用回調(diào)的情形重罪。(emmmm,這些情形不是示例中那樣強(qiáng)行回調(diào)哀九,而是你在這些情況使用回調(diào)會(huì)覺得剿配,這里使用回調(diào)真的是太酷炫,太省事啦)
? ? ?1.定時(shí)器阅束。這個(gè)是函數(shù)內(nèi)部已經(jīng)實(shí)現(xiàn)的功能呼胚,我們?cè)谑褂胹etTimeout和setInterval的時(shí)候其實(shí)就是傳入了一個(gè)回調(diào)函數(shù)。不過擴(kuò)展一下息裸,其實(shí)蝇更,這種情形是符合那種完全不知道函數(shù)該干什么的情況,但是至少我們知道這個(gè)函數(shù)是要多少時(shí)間后執(zhí)行呼盆,這樣的情況我認(rèn)為一般只會(huì)出現(xiàn)像定時(shí)器一樣這種比較底層的設(shè)計(jì)之中年扩,在具體使用回調(diào)的時(shí)候,這樣的情況太難把控了访圃。這可以總結(jié)為第一種情況厨幻,只知道模糊的回調(diào)前提,基本對(duì)回調(diào)函數(shù)沒有什么多余的限制腿时,全部交給回調(diào)函數(shù)的編寫者况脆,比較難以把控。
? ? ?2.修改指向性變量(我不知道要改什么)批糟。這一個(gè)是我這一周遇到的情況格了,我有一個(gè)需要改變的對(duì)象數(shù)組panelsData,panelsData的每一項(xiàng)(暫時(shí)寫作panelData跃赚,我在代碼中也是這么寫的)panelData都有很多的屬性笆搓,而且這個(gè)對(duì)象是要傳入到微信小程序的wxml之中的,也就意味著我如果需要修改panelsData中的某一項(xiàng)纬傲,那么必須先要?jiǎng)?chuàng)建一個(gè)克隆對(duì)象满败,在修改之后再進(jìn)行一次setData。
????現(xiàn)在解釋到這里叹括,我們已經(jīng)有了大致的函數(shù)流程
比較麻煩的就是修改對(duì)象中的某一項(xiàng)的某個(gè)屬性算墨,因?yàn)檫@個(gè)會(huì)根據(jù)實(shí)際情形出現(xiàn)不同的情況,我一開始是想通過傳入?yún)?shù)改變的汁雷,但是感覺傳入進(jìn)去净嘀,會(huì)產(chǎn)生多種麻煩(當(dāng)然現(xiàn)在想來报咳,有對(duì)象字面量的話,似乎是我考慮不周)挖藏。這時(shí)就輪到回調(diào)函數(shù)登場了暑刃,這里只需要一個(gè)callback,callback的具體功能就是修改panelsData中的某一個(gè)panelData的某一個(gè)屬性膜眠,好了岩臣,剩下的留到實(shí)際使用的時(shí)候決定吧,畢竟那時(shí)候可以確定是哪一項(xiàng)哪一個(gè)屬性宵膨,直接選取賦值就好了架谎。
? ? 3.數(shù)組遍歷類型(類似underscore,我不知道要怎么改)辟躏。最后一種與上一種其實(shí)是反過來的谷扣,我們知道要改動(dòng)的對(duì)象是什么,但是我們不知道要如何改動(dòng)捎琐,就像underscore.js中的內(nèi)容会涎,我們不知道使用者要對(duì)這個(gè)數(shù)組做什么,所以留下一個(gè)供使用者發(fā)揮自己功能的函數(shù)野哭,除了對(duì)這個(gè)數(shù)組進(jìn)行遍歷在塔,使用者還可以對(duì)他們進(jìn)行額外的操作幻件。
_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]
_.map([[1, 2], [3, 4]], _.first);
=> [1, 3]
4.最后是一些比較表層的簡化方式拨黔,這里先不細(xì)說了,不過也很重要:添加注釋绰沥,統(tǒng)一命名@橛!
結(jié)語:簡化函數(shù)的路真的是茫茫無邊徽曲,因?yàn)榇a的優(yōu)化是無止盡的嘛零截。這一周還是沒用markdown,下周寫一個(gè)markdown初步學(xué)習(xí)把M撼肌涧衙!~~