JavaScript | ES6+ 文法:関数の進化 – デフォルト引数

JavaScript
スポンサーリンク

デフォルト引数とは何か

デフォルト引数は、関数のパラメータに「未指定(または undefined)のときに使われる初期値」を直接書ける仕組みです。ここが重要です:未指定・undefined のときだけ既定値が発動します。null や 0 のような“明示的に渡された値”はそのまま使われ、既定値には置き換わりません。

function priceWithTax(price, rate = 0.1) {
  return Math.round(price * (1 + rate));
}

priceWithTax(100);              // 110(rate の既定値 0.1)
priceWithTax(100, 0.08);        // 108(渡された値を採用)
priceWithTax(100, undefined);   // 110(undefined → 既定値が効く)
priceWithTax(100, null);        // NaN(null はそのまま使われるので注意)
JavaScript

基本文法と評価のタイミング

デフォルト引数は左から右へ順番に評価されます。後ろのパラメータの既定値が前のパラメータに依存する場合、その時点で前の値はすでに決まっています。ここが重要です:既定値には式も書けるため、前の引数や外部の定数に連動できます。

const RATE = 0.1;

function total(price, rate = RATE, add = p => p * rate) {
  // add はその場で作られる関数(rate に依存)
  return Math.round(price + add(price));
}

total(100);        // 110(RATE=0.1 を使用)
total(100, 0.08);  // 108(rate=0.08 を add が使う)
JavaScript

undefined と null の違い(重要ポイントの深掘り)

ここが重要です:既定値が効くのは「未指定」か「undefined」のときだけです。null は「値あり」とみなされ、既定値にはならないため、必要なら null を補正するロジックを自分で書きます。

function nOr(n = 0) { return n; }
nOr();           // 0(未指定 → 既定値)
nOr(undefined);  // 0(undefined → 既定値)
nOr(null);       // null(既定値は発動しない)
JavaScript

null/undefined をまとめて既定値にしたいなら、Null 合体演算子(??)を使うと安全です。

function safeRate(rate) { return rate ?? 0.1; }  // null/undefined のとき 0.1
JavaScript

オブジェクト引数と分解の組み合わせ(欠けても安全)

設定オブジェクトを受け取る関数では、分割代入とデフォルト引数の組み合わせが強力です。ここが重要です:引数そのものが未指定でも安全に動かすため、外側に {} の既定値を必ず付けます。

function makeUrl(
  base,
  { q = "", page = 1, per = 20, sort = "new" } = {}   // 外側に {} を必ず
) {
  const params = new URLSearchParams({ q, page, per, sort });
  return `${base}?${params.toString()}`;
}

makeUrl("/search");                         // /search?q=&page=1&per=20&sort=new
makeUrl("/search", { q: "js", per: 5 });    // 欠けた分は既定値
JavaScript

API のフィールド名をそのまま使いたくない時は、分解で名前を変えつつ既定値を与えられます。

function shapeUser({ user_id: id, display_name: name = "" } = {}) {
  return { id, name: name.trim() };
}
JavaScript

配列引数の分解と既定値(位置ベースで安全に)

配列を受けるときも、分解+既定値で不足分を埋められます。ここが重要です:外側に [] の既定値を付けて、未指定でもエラーなく動かします。

function toPoint([x = 0, y = 0] = []) {
  return { x, y };
}

toPoint([5]);   // { x: 5, y: 0 }
toPoint();      // { x: 0, y: 0 }
JavaScript

先頭だけ取りたい、残りは任意で受けたい場合は残余引数と併用します。

function logFirst([first, ...rest] = []) {
  console.log("first:", first, "others:", rest);
}
JavaScript

宣言順(TDZ)と外部参照の注意

デフォルト引数の式で、まだ初期化されていない外部変数に触れるとエラーになります(TDZ: Temporal Dead Zone)。ここが重要です:外部の定数・変数を参照する場合は“宣言済み”の順序を守ること。

// NG(y は宣言前 → ReferenceError)
// function f(x = y) { return x; }
// let y = 5;
JavaScript

実務パターン(API を短く安全にする)

コールバックやオプションを持つ関数は、デフォルトを賢く設計すると“呼び出し側が最小記述”で済みます。ここが重要です:標準的な動きを既定値で表し、必要な箇所だけ上書きできるようにします。

// データ取得テンプレート:既定は JSON 解析+ログ
async function fetchAndRender(url, parse = r => r.json(), render = console.log) {
  const res = await fetch(url);
  if (!res.ok) throw new Error("fetch failed");
  const data = await parse(res);
  render(data);
}

// 必要な部分だけ差し替え
fetchAndRender("/api/items");  // 既定で動く
fetchAndRender("/api/items", undefined, data => {
  document.querySelector("#out").textContent = JSON.stringify(data);
});
JavaScript

設定オブジェクトを受けるユーティリティも、欠けた値を既定で埋めて“壊れにくい”インターフェースにできます。

function connect({ host = "localhost", port = 5432, ssl = false } = {}) {
  return `postgres://${host}:${port}?ssl=${ssl}`;
}
JavaScript

よくある落とし穴と回避策(重要ポイントの深掘り)

未指定のオブジェクト分解で外側 {} を忘れると「Cannot destructure property … of undefined」で落ちます。必ず外側に既定値を付けます。null を“未指定”と誤解しない、複雑な依存関係を既定値で無理に表現しない(読みづらくなる)ことも大切です。重い関数やオブジェクトを既定値で毎回生成するとコストがかさむため、共有できるものは外に出して参照を渡す設計にします。

const defaultRender = console.log;
function show(data, render = defaultRender) { render(data); }
JavaScript

例題で理解を固める

// 1) 集計:既定は“有効データのみ、価格合計”
function sum(rows, pick = r => r.price ?? 0, filter = r => r.active === true) {
  return rows.filter(filter).reduce((s, r) => s + pick(r), 0);
}

const rows = [
  { id: 1, active: true,  price: 100 },
  { id: 2, active: false, price: 200 },
  { id: 3, active: true,  price: 300 },
];

sum(rows);                             // 400(有効のみ合計)
sum(rows, r => r.price * 1.1);         // 税込みで合計
sum(rows, undefined, r => true);       // 全件合計(= 600)

// 2) URL 生成:欠けても安全
function buildUrl(base, { q = "", page = 1, per = 20, sort = "new" } = {}) {
  const params = new URLSearchParams({ q, page, per, sort });
  return `${base}?${params}`;
}
buildUrl("/search");                         // 既定値で生成
buildUrl("/search", { q: "js", per: 5 });    // 欠けた分は既定

// 3) 配列引数:不足分を既定値で埋める
function sumFirstTwo([a = 0, b = 0] = []) { return a + b; }
sumFirstTwo([2]);     // 2
sumFirstTwo();        // 0
JavaScript

まとめ

デフォルト引数の核心は「未指定・undefined にだけ既定値を適用し、呼び出し側を短く安全にする」ことです。undefined と null の違いを理解し、評価は左から右、外部参照は宣言順(TDZ)に注意する。設定オブジェクトには分割代入+外側 {} の既定値を必ず付け、配列は位置ベースで不足分を埋める。標準的な動きを既定値で表現して“必要なところだけ上書き”できる API にすれば、初心者でも壊れにくく読みやすい ES6+ の関数を設計できます。

タイトルとURLをコピーしました