JavaScriptの可変長引数(rest parameters)の活用テクニック
生徒
「先生、JavaScriptで関数の引数をいくつでも受け取れるようにする方法はありますか?」
先生
「はい、あります。『可変長引数』という仕組みを使います。英語では rest parameters と言います。」
生徒
「具体的にはどうやって書くんですか?例えば、人数が違うときに合計点を計算したいんですが。」
先生
「それなら、rest parametersを使うと便利です。順を追って説明しますね!」
1. 可変長引数(rest parameters)とは?
可変長引数とは、関数に渡す引数の数が決まっていなくても、まとめて受け取れる仕組みです。
例えば、合計を計算する関数で、人数や点数が毎回違っても対応できます。
rest parametersは、関数の引数の前に「...」を付けて書きます。
2. rest parametersの基本的な書き方
rest parametersは次のように使います。引数名の前に「...」を付けるだけです。
function sum(...numbers) {
let total = 0;
for (let num of numbers) {
total += num;
}
return total;
}
console.log(sum(10, 20)); // 30
console.log(sum(5, 15, 25, 35)); // 80
console.log(sum()); // 0
この例では、sum関数はいくつでも引数を受け取り、すべて足し合わせて返しています。
3. rest parametersと配列の関係
rest parametersは、受け取った引数を自動で配列にまとめてくれます。
配列(array)とは、複数のデータをまとめて扱うためのものです。つまり、numbersは配列として扱えます。
配列の中身を順に見るために、for文やfor...of文を使うのが一般的です。
4. rest parametersを使うメリット
- 引数の数を気にせず関数を作れる
- コードがシンプルで読みやすくなる
- 不特定多数の値を扱う処理が楽になる
例えば、ショッピングカートの合計金額を計算したり、複数のテスト点数の平均を求めたりするときに役立ちます。
5. 通常の引数とrest parametersを組み合わせる
rest parametersは、他の引数と一緒に使えます。ただしrest parametersは必ず最後に書かなければいけません。
function introduce(greeting, ...names) {
console.log(greeting);
for (let name of names) {
console.log(name + "さん");
}
}
introduce("こんにちは", "太郎", "花子", "次郎");
この例では、最初のgreetingは普通の引数で、それ以降の人の名前をrest parametersで受け取っています。
6. 使うときの注意点
rest parametersは関数の最後の引数である必要があり、複数使うことはできません。
また、rest parametersは配列なので、配列用のメソッド(例: map, filter, reduce)も使えます。
function multiplyAll(...nums) {
return nums.map(x => x * 2);
}
console.log(multiplyAll(1, 2, 3)); // [2, 4, 6]
7. rest parametersとargumentsオブジェクトの違い
JavaScriptには昔からargumentsという「関数に渡された全ての引数」をまとめた特別なオブジェクトがあります。
しかし、argumentsは配列ではなく似たもの(配列のようなオブジェクト)なので、使いにくい面があります。
rest parametersは配列として扱えるので、argumentsより便利でおすすめです。
// argumentsの例(配列ではない)
function oldSum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(oldSum(1, 2, 3)); // 6
8. 実用的な活用例:平均点を計算する関数
rest parametersを使って複数の点数を渡し、その平均を計算する関数を書いてみましょう。
function average(...scores) {
if (scores.length === 0) return 0;
let sum = scores.reduce((acc, val) => acc + val, 0);
return sum / scores.length;
}
console.log(average(80, 90, 100)); // 90
console.log(average(70, 85)); // 77.5
console.log(average()); // 0
これで点数の数が変わっても、簡単に平均を求められます。
9. rest parametersまとめの代わりのポイント
- rest parametersは「...」をつけて引数を配列として受け取る仕組み
- 引数の数が変わる関数を簡単に作れる
- 配列として扱えるのでfor文や配列メソッドが使いやすい
- 通常の引数と組み合わせて使えるが、最後に書くことが必須
argumentsオブジェクトより扱いやすくてモダンな方法
ぜひJavaScriptで関数を作るときにrest parametersを使って、コードをもっと便利にしましょう!
まとめ
ここまでJavaScriptにおける可変長引数(rest parameters)の基礎から応用、そして従来のargumentsオブジェクトとの違いについて詳しく解説してきました。モダンなJavaScript(ES6以降)の開発現場では、この「...」を用いた記法はもはや必須のスキルと言っても過言ではありません。
可変長引数がもたらすコードの柔軟性と保守性
プログラミングにおいて、関数に渡されるデータの数が事前に決まっていないケースは多々あります。例えば、ECサイトのショッピングカート内で商品の合計金額を計算する場合や、SNSアプリで複数のユーザーIDを一括で処理する場合などです。可変長引数を利用することで、引数の個数に応じたオーバーロードのような複雑な処理を書く必要がなくなり、一つの関数でスマートに完結させることができます。
また、可変長引数は「本物の配列」として渡される点が最大のメリットです。これにより、モダンJavaScriptで多用されるmapやfilter、reduceといった強力な配列メソッドをそのまま適用できます。これは、一昔前のJavaScriptで使われていたargumentsオブジェクトにはなかった大きな利点です。
実践的なサンプルコード:データフィルタリング
ここでは、特定の条件(例えば合格点以上)に合致するスコアだけを抽出して合計を出すような、少し応用的なプログラムを紹介します。実務でも、入力された複数の値から特定の条件で絞り込みを行う処理は非常によく使われます。
function sumHighScores(threshold, ...scores) {
// threshold(閾値)を超えるスコアだけを抽出して合計する
const filteredScores = scores.filter(score => score >= threshold);
return filteredScores.reduce((total, score) => total + score, 0);
}
// 80点以上のスコアだけを合計する
const result1 = sumHighScores(80, 95, 70, 85, 60, 100);
console.log("80点以上の合計:", result1);
// 60点以上のスコアだけを合計する
const result2 = sumHighScores(60, 55, 80, 40, 75);
console.log("60点以上の合計:", result2);
実行結果は以下のようになります。
80点以上の合計: 280
60点以上の合計: 155
スプレッド構文との混同に注意
初心者の方がよく躓くポイントとして、可変長引数(rest parameters)と同じ「...」記号を使う「スプレッド構文(spread syntax)」との違いがあります。 可変長引数は「バラバラの引数を一つにまとめる」役割ですが、スプレッド構文は「一つの配列をバラバラに展開する」役割です。 関数の定義側で使うのがrest parameters、関数を呼び出す側(実引数)や配列の結合などで使うのがスプレッド構文だと覚えておくと整理しやすいでしょう。
TypeScriptでの型定義について
もしあなたがTypeScriptを使っているなら、可変長引数にも型を指定する必要があります。配列として受け取るため、型名の後ろに[]を付けるのが基本です。
function logMessages(prefix: string, ...messages: string[]): void {
messages.forEach(msg => {
console.log(`${prefix}: ${msg}`);
});
}
logMessages("通知", "システムを起動しました", "ログインに成功しました");
生徒
先生、まとめありがとうございます!可変長引数を使うと、引数の数をあらかじめ決めなくていいので、関数の汎用性が一気に高まる感じがしますね。
先生
その通りです。これまではargumentsを使って苦労して配列に変換していた処理も、今では「...」を書くだけで最初から配列として扱えるので、コードの見通しが本当に良くなりました。
生徒
さっきのサンプルコードを見て気づいたのですが、普通の引数と混ぜて使うときは、可変長引数を最後に置かないとエラーになっちゃうんですよね?
先生
よく気づきましたね!JavaScriptのエンジンは、どこまでが普通の引数で、どこからが「残りの全て(rest)」なのかを判断する必要があります。そのため、可変長引数は必ず一番最後に配置するというルールがあるんです。試しに可変長引数を先頭に書いてみると、構文エラー(SyntaxError)が発生してプログラムが動かなくなりますよ。
生徒
なるほど。「残りの引数を全部引き受ける」というイメージで覚えれば、最後に書く理由もしっくりきます。配列メソッドのreduceやfilterとの相性がいいのも、モダンな書き方っぽくてかっこいいです!
先生
そうですね。特に関数型プログラミングのようなスタイルを取り入れる際は、可変長引数と配列メソッドの組み合わせは強力な武器になります。これから複雑なロジックを組む際にも、ぜひ積極的に使ってみてください。コードが驚くほどスッキリするはずです。
生徒
はい!まずは自分で作っている家計簿アプリの合計金額計算の部分を、この可変長引数を使って書き直してみようと思います。ありがとうございました!