參數越多,理解成本越高。
問個簡單的問題:當你看到一行程式碼 createUser('Bob', 'bob@h.com', 42, true, false)
,你知道那兩個 true
和 false
是什麼意思嗎?
不知道,沒有人知道,必須要回去翻原始碼,生命又消逝了好幾秒好幾分鐘。
一個好的函式,應該像一個設計良好的網頁表單,每個輸入框前面都有清晰的標籤。
用物件收斂參數,避免傳布林參數改流程。
一個 true
或 false
的參數,實際上是在告訴世界:「這個函式偷偷地在做兩件完全不同的事,具體做哪件,取決於你傳入的這個神秘開關。」
// 🔴 臭味:這是一個糟糕的 API。它難以閱讀、容易出錯、無法擴展。
function createUser(name, email, age, isAdmin, sendWelcomeEmail) { /* ... */ }
// 呼叫點就是一串密碼。isAdmin 在前還是 sendWelcomeEmail 在前?誰記得住?
createUser('Eve', 'eve@h.com', 30, false, true);
// 如果順序錯了,bug 就產生了,而且很難被發現。
createUser('Mallory', 'm@h.com', 99, true, false);
// 原本想發送郵件,結果變成了管理員
// 這個函式身兼數職,而且還不寫在它的名片上。
這違反了單一職責原則 (Single Responsibility Principle,SRP)。
一個函式應該只做一件事,並把它做好。
當你用一個布林參數來切換兩種行為時,代表這個函式至少做了兩件事。
這就是臭味的來源。
改用一個物件,讓每個參數都有自己的名字。
// 🟢 好品味:這是一個自我說明的、穩定的 API。
// 函式只接受一個物件,參數就像有了標籤,清晰易懂。
/**
* 主要函式:建立使用者。
*/
function createUser({ name, email, age, role = 'member' }) {
// ✅ 具名參數 : 透過解構賦值 { name, ... },參數的順序不再重要。
// ✅ 預設值 : `role = 'member'` 提供了穩定的預設行為。
// ✅ 優化模型 : 用 'role' (字串) 取代 'isAdmin' (布林),未來更有擴充性。
console.log(` [主要] 正在建立使用者 ${name},角色為 ${role}...`);
return { name, email, age, role };
}
/**
* 獨立職責:寄送 Email 的行為被分離出來,專注做一件事。
*/
function sendWelcomeEmail(user) {
console.log(` [行為] 正在寄送歡迎信給 ${user.email}...`);
}
/**
* 特殊流程:當行為模式顯著不同時,提供一個新的、命名清晰的函式。
* 這遠比在 createUser 內部用 if (isAdmin) ... else ... 要好。
*/
function createAdminUser({ name, email, age }) {
console.log("-> 開始「建立管理員」的特殊流程...");
// ✅流程組合: 重複利用 `createUser` 的核心功能,並添加額外步驟。
const adminUser = createUser({ name, email, age, role: 'admin' });
console.log(` [特殊] 正在為管理員 ${adminUser.name} 設定特殊權限...`);
console.log("-> 管理員流程結束。");
return adminUser;
}
// --- 實際呼叫點 (The Call Site) ---
// 情境一:建立普通使用者
// ✅可讀性高: 呼叫點像在填寫一份有標籤的表單,意圖一目了然。
const user1 = createUser({
name: 'Eve',
email: 'eve@example.com',
age: 30
});
// ✅【行為組合】: 可以彈性地組合 `createUser` 和 `sendWelcomeEmail`。
sendWelcomeEmail(user1);
console.log("\n情境二:建立管理員");
// ✅意圖明確: 直接呼叫 `createAdminUser`,程式碼的意圖非常清楚。
const admin1 = createAdminUser({
name: 'Mallory',
email: 'mallory.admin@example.com',
age: 42
});
// (根據需求,管理員可能不需要寄送一般歡迎信,行為可以自由組合)
它自我說明: name: 'Eve'
這樣的寫法,程式碼自己就解釋了參數的意義。
它穩定且可擴展: 參數的順序無關緊要。未來如果需要增加新的可選參數,直接在物件裡增加屬性就行,完全不會破壞任何舊的呼叫程式碼。
它強迫你做出更好的設計: 把布林參數 isAdmin
改成 role
,優化資料模型。
把 sendWelcomeEmail
這個行為從 createUser
裡分離出來,讓每個函式只做一件事,這才對。
true/false
。一個開關代表「兩種行為/職責」,請把函式一分為二。停止折磨你的同事和未來的你自己。
開始為你的函式設計真正好用的介面。