プログラミングを始めたばかりだと「…(ドット3つ)」が何をしているのか戸惑いますよね。rest パラメータは「引数の数が決まっていなくても関数で受け取れる」便利な仕組みです。例を交えながら、直感的に理解できるように説明します。
基本の考え方と書き方
- 意味: 関数定義で
...名前と書くと、余った引数を「配列」としてまとめて受け取れます。 - 場所: rest は「最後の引数」しか置けません。
- 数: rest は「1つだけ」しか定義できません。
function sum(...numbers) {
// numbers は配列なので、for や reduce が使える
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
JavaScriptrest で受け取った値は配列として扱えるため、map / filter / reduce などがそのまま使えます。また、仕様上、rest は最後に1つだけ、末尾のカンマ不可、デフォルト値不可などの制約があります。
固定引数+rest の実例
- パターン: 最初のいくつかは「必須の固定引数」、残りは「まとめて」受け取る。
function greet(greeting, ...names) {
return `${greeting}, ${names.join(' and ')}!`;
}
console.log(greet("Hello", "Alice", "Bob", "Charlie"));
// "Hello, Alice and Bob and Charlie!"
JavaScriptこのように、固定の引数の後ろに rest を置くと、柔軟で読みやすい関数が書けます。
rest と「スプレッド構文」の違い
同じ「…」でも、使う場所で役割が変わります。
- rest: 関数「定義」の引数で使い、余りを「集めて配列化」する。
- spread: 関数「呼び出し」や配列リテラルで使い、配列やオブジェクトを「展開」する。
function multiply(x, y, z) {
return x * y * z;
}
const numbers = [1, 2, 3];
console.log(multiply(...numbers)); // 6 ← 呼び出し側の「展開」が spread
JavaScript配列を他の配列へ自然に差し込んだり、関数へ配列をそのまま渡すときに spread を使います。ES2015 以降では apply の代わりに spread が読みやすくて主流です Qiita Note。
arguments との違い(初心者がつまずきやすい所)
- arguments: 配列「風」オブジェクト。
mapなどが直接使えない。アロー関数では存在しない。 - rest: 本物の配列。
map / filter / reduceがすぐ使える。アロー関数でも使える。
// arguments だと配列メソッドが使いづらい
function oldSum() {
// [...arguments] として配列化が必要
return [...arguments].reduce((t, n) => t + n, 0);
}
// rest なら最初から配列
const newSum = (...nums) => nums.reduce((t, n) => t + n, 0);
JavaScript可読性と柔軟性の面で、今は rest の利用が推奨されます。
よくある使い方パターン
- 可変長の合計や統計処理:
function average(...nums) {
if (nums.length === 0) return 0;
const sum = nums.reduce((t, n) => t + n, 0);
return sum / nums.length;
}
JavaScript- 最初の引数が「設定」や「オプション」、残りがデータ:
function logWithLevel(level, ...messages) {
console.log(`[${level}]`, ...messages);
}
logWithLevel("INFO", "Server started", { port: 8080 });
JavaScript- 第一引数を「基準」として、残りに同じ処理を適用:
function startsWith(prefix, ...texts) {
return texts.map(text => text.startsWith(prefix));
}
console.log(startsWith("pre", "prefix", "preview", "next")); // [true, true, false]
JavaScript- コマンド風 API の設計(サブコマンド+引数群):
function run(cmd, ...args) {
switch (cmd) {
case "add":
return args.reduce((t, n) => t + n, 0);
case "mul":
return args.reduce((t, n) => t * n, 1);
default:
throw new Error(`Unknown command: ${cmd}`);
}
}
console.log(run("add", 1, 2, 3)); // 6
console.log(run("mul", 2, 3, 4)); // 24
JavaScriptrest で受け取った配列を使い回すことで、柔軟なインターフェースを簡潔に書けます。
仕様上の注意点(落とし穴を避ける)
- 最後にしか置けない:
function f(...rest, a)はエラー。function f(a, ...rest)は OK。 - 1つだけ:
function f(...a, ...b)は不可。 - デフォルト値不可:
function f(...rest = [])は不可。 - 末尾カンマ不可:
function f(...rest,)は不可。 - 空呼び出しでも配列: 引数ゼロなら
restは[]になる。 - 広く動作: 主要ブラウザと Node.js で広く利用可能(ES2015 以降)。
手を動かす練習問題
- 練習1: min/max
- 課題:
min(...nums)とmax(...nums)を rest で作成。 - ヒント:
Math.min(...nums)のように spread で展開。
- 課題:
- 練習2: ユニーク化
- 課題:
unique(...items)が重複を除いた配列を返す。 - ヒント:
return [...new Set(items)];
- 課題:
- 練習3: フォーマッタ
- 課題:
format(template, ...values)で${0},${1}を values で置換。 - ヒント:
replace(/\$\{(\d+)\}/g, (_, i) => String(values[Number(i)] ?? ''))
- 課題:
直感メモ(覚え方)
- rest は「受け皿」: 関数の中で余った引数を「配列にまとめる」。
- spread は「取り分け」: 配列やオブジェクトを「ばらして渡す/差し込む」。
- arguments より rest: モダン JS では配列の rest を使う方が自然で読みやすい。
