函數的參數越少越好 有一個準則是:如果你的函數參數超過兩個,就應該改為對象傳入。 這樣做是合理的,因為當函數參數超過兩個時,參數順序開始變得難以記憶,而且容易出現一種很尷尬的情況:比如我只需要傳入第三個參數,因為其自身順序的原因,不得不補齊前兩個根本用不上的參數,以讓它順利排在第三位。 // bad ...
函數的參數越少越好
有一個準則是:如果你的函數參數超過兩個,就應該改為對象傳入。
這樣做是合理的,因為當函數參數超過兩個時,參數順序開始變得難以記憶,而且容易出現一種很尷尬的情況:比如我只需要傳入第三個參數,因為其自身順序的原因,不得不補齊前兩個根本用不上的參數,以讓它順利排在第三位。
// 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參數比較多,函數內部的區分情況也會很多。
另外這裡也涉及一種思想:具體的差異實現應該由使用者提供,而不是統一執行者去維護。
或者稱之為依賴倒置原則:高層模塊(列印)不應該依賴於實現細節(某個人的喜好)。
比如,我現在有一臺印表機