こんにちは、かつコーチです。
前回はスプレッド構文と残余引数を解説しました。
今回は基本に立ち返って、「デフォルト引数」を扱います。
関数の引数が渡されなかったときに困った経験がある人は多いと思いますが、デフォルト引数を使えば、そうした場面をとてもシンプルに解決できます。
デフォルト引数とは?
引数が渡されなかったときの初期値
デフォルト引数とは、関数を呼び出す際に引数が渡されなかった場合に使われる「初期値」を、あらかじめ設定しておく仕組みです。
ES2015(ES6)から使えるようになりました。
function greet(name = "ゲスト") {
console.log(`こんにちは、${name}さん!`);
}
greet("かつコーチ");
// 出力: こんにちは、かつコーチさん!
greet();
// 出力: こんにちは、ゲストさん!
引数 name に = "ゲスト" と書いておくことで、引数を渡さずに呼び出したときは自動的に "ゲスト" が使われます。
なぜ必要なのか
デフォルト引数が登場する前は、引数が渡されなかった場合の処理を、関数の中で自分で書く必要がありました。
// 従来の書き方:関数の中で「渡されなかった場合」を判定する
function greetOld(name) {
if (name === undefined) {
name = "ゲスト";
}
console.log(`こんにちは、${name}さん!`);
}
greetOld();
// 出力: こんにちは、ゲストさん!
引数が増えるたびにこの if 文を書く必要があり、本来の処理とは関係のないコードが関数の中に増えていきます。
デフォルト引数を使えば、この「値が渡されなかったときの処理」を引数の定義部分に集約でき、関数の中身をすっきり保てます。
基本の書き方
シンプルなデフォルト値の設定
デフォルト引数は、引数名の後ろに = 初期値 を書くだけで設定できます。
function calcTax(price, taxRate = 0.1) {
return price * (1 + taxRate);
}
console.log(calcTax(1000));
// 出力: 1100(taxRateは省略されたので0.1が使われる)
console.log(calcTax(1000, 0.08));
// 出力: 1080(taxRateを明示的に指定した場合はそちらが優先される)
引数を明示的に渡した場合は、デフォルト値ではなく渡された値が優先されます。
複数の引数にデフォルト値を設定する
複数の引数にそれぞれデフォルト値を設定することもできます。
function createUser(name = "ゲスト", role = "一般会員") {
return `${name}さん(${role})`;
}
console.log(createUser());
// 出力: ゲストさん(一般会員)
console.log(createUser("かつコーチ"));
// 出力: かつコーチさん(一般会員)
console.log(createUser("かつコーチ", "管理者"));
// 出力: かつコーチさん(管理者)
他の引数の値を使ってデフォルト値を計算する
デフォルト値には、他の引数を使った計算式を書くこともできます。
function createBox(width, height = width) {
return `幅${width}、高さ${height}の箱`;
}
console.log(createBox(100));
// 出力: 幅100、高さ100の箱(heightが省略されたのでwidthと同じ値になる)
console.log(createBox(100, 50));
// 出力: 幅100、高さ50の箱
先に定義されている引数(この例では width)は、後の引数のデフォルト値の中で参照できます。
つまずきやすいポイント:undefined 以外では発動しない
0 や "" を渡してもデフォルト値に置き換わらないと誤解していた
私が実際につまずいたのは、デフォルト引数が発動する条件についてです。
「渡された値が空っぽっぽいときにデフォルト値が使われる」と思い込んでいたのですが、実際には引数が undefined のときにしかデフォルト値は使われません。
これに気づかず、数値の 0 を渡しているのに意図しない値に上書きされる、という逆向きのバグに悩まされたことがあります。
❌ Before:0 を「値なし」として扱ってしまうコード
function setDiscount(rate = 10) {
console.log(`割引率は${rate}%です`);
}
// 割引なし(0%)のつもりで明示的に0を渡した
setDiscount(0);
// 出力: 割引率は0%です(これは意図通り。デフォルト引数はundefinedのときだけ発動する)
このコード自体は正しく動くのですが、私は当時「0 は空っぽの値だから、きっとデフォルト値の 10 に置き換わってしまうはずだ」と誤解していました。
その誤解のまま、次のように自分で余計なチェックを書いてバグを生んでしまいました。
function setDiscountBuggy(rate = 10) {
// 「0はfalsyだからデフォルト値が使われていないか心配」という誤解から
// 余計なOR演算子でのフォールバックを追加してしまった
const finalRate = rate || 10;
console.log(`割引率は${finalRate}%です`);
}
setDiscountBuggy(0);
// 出力: 割引率は10%です(0を指定したのに10になってしまう)
rate || 10 という書き方は、rate が 0 や "" のような「falsy(偽と判定される値)」のときにもデフォルト値へ置き換えてしまいます。
0 という正しい入力値が、意図せず 10 に上書きされてしまったわけです。
✅ After:デフォルト引数だけに任せて余計なチェックを書かない
function setDiscount(rate = 10) {
console.log(`割引率は${rate}%です`);
}
setDiscount(0);
// 出力: 割引率は0%です(意図通り)
setDiscount();
// 出力: 割引率は10%です(引数を渡さなかった場合のみデフォルト値が使われる)
デフォルト引数はあくまで「引数が渡されなかった(undefined の)場合」にだけ発動する仕組みです。
0 や "" 、false といった値は、意図的に渡された正しい値としてそのまま扱われます。
|| を使った独自のフォールバック処理を安易に追加すると、こうした値まで巻き込んで上書きしてしまうので注意が必要です。
応用:オブジェクトの分割代入と組み合わせる
オプション引数のパターン
デフォルト引数は、分割代入と組み合わせることで「オプションをオブジェクトで渡す」パターンにも使えます。
実務でよく見る書き方なので、ここで押さえておきましょう。
function createUser({ name = "ゲスト", role = "一般会員" } = {}) {
console.log(`${name}さん(${role})`);
}
createUser({ name: "かつコーチ" });
// 出力: かつコーチさん(一般会員)
createUser();
// 出力: ゲストさん(一般会員)
{ name = ..., role = ... } = {} のように、分割代入自体にもデフォルト値の {} を設定しておくのがポイントです。
これを忘れると、引数なしで呼び出したときに「undefined から分割代入しようとしてエラーになる」という別のつまずきにつながるので、セットで覚えておくと安心です。
まとめ
この記事のポイント
- デフォルト引数は、引数が渡されなかったときの初期値を設定できる仕組み
引数名 = 初期値という書き方で設定する- デフォルト値は「引数が
undefinedのとき」にだけ発動する 0や""のような値は、渡された正しい値としてそのまま扱われる||による独自のフォールバックとデフォルト引数を混同すると意図しない上書きが起きる- オブジェクトの分割代入と組み合わせると、オプション引数のパターンが書ける
次に読むべき記事
次回は「クロージャをわかりやすく解説」します。
関数の中で変数がどう記憶されるのかという、JavaScriptらしい仕組みを理解できる回です。
→ 次の記事:クロージャをわかりやすく解説