函式的引數越少越好
有一個準則是:如果你的函式引數超過兩個,就應該改為物件傳入。
這樣做是合理的,因為當函式引數超過兩個時,引數順序開始變得難以記憶,而且容易出現一種很尷尬的情況:比如我只需要傳入第三個引數,因為其自身順序的原因,不得不補齊前兩個根本用不上的引數,以讓它順利排在第三位。
// bad
const createArticle = (title, author, date, content) => { }
createArticle('震驚,一男子竟偷偷幹這事', 'zhangnan', '2020/06/29', '某天深夜,我喝多了點酒...')
// good
const createArticle = ({title, author, date, content}) => { }
createArticle({
title: '震驚,一男子竟偷偷幹這事',
author: 'zhangnan',
date: '2020/06/29',
content: '某天深夜,我喝多了點酒...'
})
保持函式的單一職責原則
這是軟體開發領域亙古不變的一個真理,讓一個函式只專注於一件事情,能夠很好的解耦各個功能之間的聯絡,使得後續對某一個功能進行更改時,不用擔心會影響其他模組。
假設我們現在有一個需求:現在需要給班裡的每一個同學發放假簡訊通知,如果是男生,就用電信主機號來發,如果是女生,則用聯通主機號發,同時額外傳送一封愛心郵件。實現如下:
// bad 程式碼擠成一堆,很難理清
// 男生女生的通知方式還有所不同,後期如果要改動女生的通知方式,很難保證不會影響到男生
// 因為大家都寫在同一個函式裡
const notifyStudents = (studentList) => {
studentList.forEach(student => {
if (student.gender === 'male') {
const sender1 = new SmsSender({ carrier: '電信' });
sender1.init();
sender1.sendTo(student)
} else {
const sender2 = new SmsSender({ carrier: '聯通' });
sender2.init();
sender2.sendTo(student);
const sender3 = new EmailSender({ type: 'QQ郵箱' });
sender3.connect();
sender3.sendTo(student)
}
})
}
// good 函式拆分,各司其職,清晰明瞭
// 雖然看起來程式碼量多了一點點
// 但是分工明確,互不影響
const initSmsSender = (carrier) => {
const sender = new SmsSender({ carrier });
sender.init();
}
const initEmailSender = (type) => {
const sender = new EmailSender({ type });
sender.connect();
}
const notifyMales = (studentList) => {
const smsSender = initSmsSender('電信');
const maleList = studentList.filter(student => student.gender === 'male');
maleList.forEach(male => smsSender.sendTo(male));
}
const notifyFemales = (studentList) => {
const smsSender = initSmsSender('聯通');
const emailSender = initEmailSender('QQ郵箱');
const femaleList = studentList.filter(student => student.gender === 'female');
femaleList.forEach(female => {
smsSender.sendTo(female);
emailSender.sendTo(female);
})
}
封裝條件語句
像有一些條件語句,可能存在很多與或非邏輯,如果直接寫在函式裡面,每次都需要重新理一遍,費時費力。把一堆條件語句封裝在一個函式裡面,不僅遵循單一職責原則,也將使得閱讀更加方便。
// bad
const shouldIBuyThisPhone = (phone) => {
const {price, year, brand} = phone;
if (price > 5000 && year === new Date.getFullYear() && brand === 'huawei') {
// 馬上剁手
}
}
// good
const isHuaweiFlagShipThisYear = ({ price, year, brand }) => {
const HIGH_PRICE = 5000;
return price > HIGH_PRICE && year === new Date.getFullYear() && brand === 'huawei'
}
const shouldIBuyThisPhone = (phone) => {
if (isHuaweiFlagShipThisYear(phone)) {
// 馬上剁手
}
}
高層函式不要依賴具體實現
在一些動作函式中,常見的一種情況是傳一個flag引數,通過對標誌變數的判斷,做出不同的響應動作。
這樣其實是不太好的,因為這會使這個動作函式內部去維護一些判斷邏輯,如果flag引數比較多,函式內部的區分情況也會很多。
另外這裡也涉及一種思想:具體的差異實現應該由使用者提供,而不是統一執行者去維護。
或者稱之為依賴倒置原則:高層模組(列印)不應該依賴於實現細節(某個人的喜好)。
比如,我現在有一臺印表機?️,小A喜歡用單面黑白橫向列印,小B喜歡用單面彩色豎向列印,小C喜歡用雙面彩色橫向列印等等等等。作為一臺印表機,它需要去維護一個人員喜好列表嗎?如果有一千個人使用它,那它就需要維護一千條資料。
它只是一臺印表機!告訴它配置,然後列印,就完事了!印表機只專注於列印這件事本身。
// bad 需要判斷標誌變數,同時做出不同的相應動作
const print = (person) => {
if (person === 'A') {
device.print({
page: 1,
color: 'gray',
orientation: 'landscape'
})
}
else if (person === 'B') {
device.print({
page: 1,
color: 'colorful',
orientation: 'vertical'
})
}
else if (person === 'C') {
device.print({
page: 2,
color: 'colorful' ,
orientation: 'landscape'
})
}
......
}
// good
const print = (config) => {
device.print(config)
}
寫在最後
總結:
- 函式傳參越少越好,多了改為物件傳入
- 保持函式單一職責原則
- 封裝條件語句
- 高層函式不要依賴具體實現
另外,幫大佬發個位元組跳動今日頭條校園招聘宣傳,北廣深均有,Inspire creativity, enrich life
。歡迎各位小鮮肉報名加入 今日頭條校招傳送門