概要
関数の引数は、関数の使い方を決定する“契約”である。
何を受け取るか、どれが必須か、何が省略可能か――それを構文として明示する設計こそが、使いやすく壊れにくいコードの鍵となる。
本稿では、以下の軸で関数引数の設計戦略を構造化する:
- 位置引数 vs オブジェクト引数の選定基準
- デフォルト値の設計と罠
- 構造分解による明示的な呼び出し
- オプション引数と“明確な不在”の伝達
- 設計判断フローと実践ユースケース
1. 基本の位置引数とその限界
function createUser(name, age, admin) {
return { name, age, admin };
}
createUser('Toto', 30, true);
- ✅ シンプル・軽量
- ❌ 引数が増えると順番が崩壊する
- ❌ オプションの挿入・スキップが難しい
2. オブジェクト引数による命名付きインターフェース
function createUser({ name, age, admin = false }) {
return { name, age, admin };
}
createUser({ name: 'Toto', age: 30 });
- ✅ 引数の意味が呼び出し側で明確に
- ✅ オプション/必須の管理が柔軟
- ✅ デフォルト値の設計も簡潔
3. 構造分解とデフォルトのコンビネーション
function notify({ message = '成功', type = 'info' } = {}) {
console.log(`[${type}] ${message}`);
}
notify(); // [info] 成功
notify({ message: '失敗', type: 'error' }); // [error] 失敗
- ✅ 全体引数が省略されても安全
- ✅ 柔軟なオプションAPIが実現可能
4. 引数の構造化:必須・任意の分離戦略
function updateUser(id, { name, age } = {}) {
// idは必須、他は任意
}
- ✅ 「絶対に必要な引数」と「設定可能な引数」を明示的に分離
5. フラグ型引数のアンチパターン
function toggle(isActive, silently) {
// ❌ silently = true の意味が曖昧
}
→ ✅ フラグではなくオプション名で渡す
function toggle(isActive, { silently = false } = {}) {
if (!silently) notifyUser();
}
6. スプレッド演算子と引数透過性
function logEvent(event, ...args) {
console.log(`[${event}]`, ...args);
}
logEvent('click', 'button#submit', 300);
- ✅ 可変長引数を扱いやすくなる
- ✅ React/Vueなどのイベント転送にも活用される
7. 設計判断フロー
① 引数が2つ以内? → 位置引数で簡潔に
② 引数が3つ以上、またはオプションあり? → オブジェクト引数へ
③ 必須と任意を分けたい? → 位置 + オブジェクト分離
④ 意図が曖昧なbooleanを使ってない? → 意味のあるキー名を使う
⑤ 柔軟な拡張を許容したい? → デフォルト値と構造分解を活用
よくある誤設計と対策
❌ フラグ引数の多用
function loadData(cache, debug, timeout) {}
→ ✅ loadData({ cache, debug, timeout })
へ構造的に変更
❌ デフォルト値を関数本体で上書き
function notify(msg) {
const message = msg || '成功'; // ❌ '', 0, false を潰す可能性あり
}
→ ✅ msg ?? '成功'
を使う or = '成功'
を引数定義時に明示
結語
関数の引数は“入口”であり、“約束”であり、“設計の意思”である。
- 意図が見えるように
- 柔軟性があっても破綻しないように
- 拡張しても読みやすいままであるように
使う人を守る関数は、インターフェースに意図が刻まれている。
設計された引数は、読む人を迷わせない。