JavaScript | デフォルト引数

JavaScript JavaScript
スポンサーリンク

それでは「実務で役立つデフォルト引数の具体例」をいくつか作って、用途・利点・注意点をコードとともに丁寧に解説します。すぐ使えるパターンを中心にします — そのままプロダクションのユーティリティに入れられるような例も含めます。

1. オプションオブジェクトのデフォルト(一般的パターン)

多くの実務コードでは「引数が増えたときに壊れない」ようにオプションをオブジェクトで受け取り、{} をデフォルトにする書き方が便利です。

function fetchData(url, options = {}) {
  const {
    method = "GET",
    headers = { "Content-Type": "application/json" },
    timeout = 5000,
    retries = 2
  } = options;

  console.log({ url, method, headers, timeout, retries });
  // 実際は fetch を使って処理する(省略)
}

fetchData("/api/users");
// => method: "GET", timeout: 5000, retries: 2

fetchData("/api/users", { method: "POST", retries: 0 });
// => method: "POST", timeout: 5000, retries: 0
JavaScript

利点:呼び出し側で必要なオプションだけ指定でき、将来オプションが増えても互換性を保てる。

2. 関数ベースの遅延評価(副作用のあるデフォルト値を遅らせる)

デフォルト値に関数呼び出しを書くと、呼ばれたときだけ評価されます。重い処理や副作用がある場合は便利です。

function expensiveSetup() {
  console.log("expensiveSetup 実行");
  return { token: "abcd" };
}

function doTask(config = expensiveSetup()) {
  console.log("config:", config);
}

doTask({ token: "user-provided" }); // expensiveSetup は呼ばれない
doTask(); // expensiveSetup が呼ばれる
JavaScript

利点:必要なときだけ重い処理を行う。呼び出しごとに別のデフォルトがほしいときにも使える。

3. パラメータ同士の依存(後続パラメータが前の値に依存)

ある引数のデフォルト値に前の引数を参照することができます(ただし左から右へ評価されます)。

function makeGreeting(name = "ゲスト", greeting = `こんにちは、${name}さん`) {
  console.log(greeting);
}

makeGreeting("太郎");        // こんにちは、太郎さん
makeGreeting();              // こんにちは、ゲストさん
makeGreeting(undefined, "やあ"); // やあ
JavaScript

注意:依存する前の引数が undefined の場合に想定どおり動くようにする。

4. デフォルト値と分割代入(関数でオブジェクトを受け取るとき)

APIレスポンス整形やコンポーネントの props に便利。

function renderCard({ title = "無題", content = "", showFooter = true } = {}) {
  console.log("title:", title);
  console.log("content:", content);
  console.log("showFooter:", showFooter);
}

renderCard(); // 引数なしでも安全に動く
renderCard({ title: "今日のニュース" });
JavaScript

ポイント:関数の引数全体にも = {} を付けないと、引数を省略したときに分割代入でエラーになります。

5. バリデーションを組み合わせた安全設計

単にデフォルト値を与えるだけでなく、渡された値の型チェックや正規化も行うと堅牢になります。

function createUser({ name = "名無し", age = 18, roles = [] } = {}) {
  // 型チェック・正規化
  if (typeof name !== "string") name = String(name);
  age = Number.isFinite(age) ? age : 18;
  roles = Array.isArray(roles) ? roles : [roles];

  return { name, age, roles };
}

console.log(createUser({ name: null, age: "25", roles: "admin" }));
// => { name: "null", age: 25, roles: ["admin"] }
JavaScript

利点:外部入力や古いクライアントからの呼び出しでも予測可能に動く。

6. デフォルト引数を使った負荷分散(例:ログ送信)

デフォルトでローカル保存、オプションでリモート送信など実務でよくあるパターン。

function sendLog(message, transport = defaultTransport) {
  transport.send(message);
}

const defaultTransport = {
  send(msg) {
    // 既定はローカルに保存
    console.log("local store:", msg);
  }
};

const remote = {
  send(msg) {
    // 実際は HTTP POST など
    console.log("sending to remote:", msg);
  }
};

sendLog("ユーザーログ");           // local store
sendLog("重要ログ", remote);      // remote
JavaScript

利点:テスト時にモックを渡すだけで外部呼び出しを差し替えられる(DI に近い使い方)。

7. 注意点まとめ(実務での落とし穴)

  • null を渡すとデフォルトは 使われないundefined のときのみ有効)。必要に応じて ??(Nullish coalescing)を使う。
function fn(x = 1) { console.log(x); }
fn(null); // null
JavaScript
  • 可変オブジェクト(配列・オブジェクト)をデフォルトにすると、参照共有のバグが発生することがある。関数で新しいオブジェクトを生成するパターンが安全。
// NG: 共有される
function pushItem(item, list = []) { list.push(item); return list; }
pushItem(1); // [1]
pushItem(2); // [1,2] ← 期待外の共有(実際は JS では初回ごとに別インスタンス。ただし注意は必要)
JavaScript

→ 安全な書き方:

function pushItem(item, list) {
  const safeList = (list === undefined) ? [] : list;
  safeList.push(item);
  return safeList;
}
JavaScript
  • 前方の引数でデフォルトを設定すると、後続引数を省略したいときに undefined を明示する必要が出ることがある。オプションはオブジェクトで渡すのがベター。

8. 練習問題(すぐ手を動かせる)

  1. greet(name = "ゲスト", punctuation = "!") を使って "やあ、太郎さん!" のように表示する関数を書いてください。
  2. makeRequest(url, { retries = 3 } = {}) を使って、retries のデフォルトが効く呼び出しと、retries = 0 が効く呼び出しの両方を示してください。

解答

function greet(name = "ゲスト", punctuation = "!") {
  console.log("やあ、" + name + "さん" + punctuation);
}
greet("太郎"); // やあ、太郎さん!
greet();       // やあ、ゲストさん!
JavaScript
function makeRequest(url, { retries = 3 } = {}) {
  console.log("URL:", url, "retries:", retries);
}
makeRequest("/ping");                     // retries: 3
makeRequest("/ping", { retries: 0 });     // retries: 0
JavaScript
タイトルとURLをコピーしました