残余引数 ...args
残余引数 ...args とは
...args で任意の数の引数を配列として受け取る。本レッスンでは、残余引数 ...args の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
残余引数で可変長を受け取る
関数を作るときに「引数の数が事前に決まっていない」場面があります。例えば「いくつかの数字を渡すと全部の合計を返す」 sum のような関数です。 sum(1, 2) でも sum(1, 2, 3, 4, 5) でも動かしたい、こんなときに使うのが 残余引数 (rest parameters) です。
残余引数は
...argsのように...(スプレッド/レスト) を引数名の前に付けることで、残りの引数すべてを配列として受け取る構文です。
古い JavaScript では arguments という特殊オブジェクトで似たことができましたが、本物の配列ではなく Array.prototype のメソッドが使えませんでした。残余引数なら最初から本物の配列なので、 forEach や reduce などがそのまま使えます。
残余引数の文法
書き方は次のとおりです。
JavaScript
function sum (...nums) {
let total = 0;
for (const n of nums) total += n;
return total;
}
console.log(sum()); // 0
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30)); // 60...nums と書くと、関数本体では nums は [1, 2, 3] のような 配列 になっています。 nums.length で個数も取れますし、 for-of で順番に処理できます。 Array.prototype.reduce を使えば一行で書くこともできます。
JavaScript
const sum2 = (...nums) => nums.reduce((acc, n) => acc + n, 0);
reduceは次のレッスンで詳しく学びますが、配列を 1 つの値にまとめるためのメソッドです。今は「合計を計算する標準的な書き方」とだけ覚えておけば OK です。
普通の引数と組み合わせる
普通の引数と残余引数を組み合わせることもできます。ただし、残余引数は 必ず最後の引数 でなければいけません。
JavaScript
function logWith (prefix, ...messages) {
return messages.map((m) => `${prefix}: ${m}`);
}
console.log(logWith('INFO', 'A', 'B', 'C'));
// ['INFO: A', 'INFO: B', 'INFO: C']スプレッド構文との違い
... は使う場所で意味が変わります。 関数の引数定義 で使えば 残余引数 、 配列を展開する場所 で使えば スプレッド構文 です。形は同じでも役割が逆方向だと覚えておきましょう。
JavaScript
// 残余 — 引数を配列に集める
function f (...args) { return args; }
f(1, 2, 3); // [1, 2, 3]
// スプレッド — 配列を要素に展開
const nums = [1, 2, 3];
Math.max(...nums); // 3
集めるvs展開する、と覚えると混乱しません。引数定義側なら集める、呼び出し側なら展開する、です。
よくある間違い
以下のとおりです。
...restを引数の途中に書く (function f (...a, b)はSyntaxError)- 残余引数を
argumentsと勘違いしてアロー関数で使う (アロー関数ではarguments自体が使えない) - 引数なしで呼び出したら
numsがundefinedになると思い込む (実際は空配列 [])
JavaScript
const sumA = (...nums) => nums.reduce((acc, n) => acc + n, 0);
sumA(); // 0 — 空配列に reduce してもエラーにならない初期値
0をreduceに渡しているのがポイントです。reduceを初期値なしで呼ぶと、空配列のとき例外になります。
実際の使いどころ
残余引数は ライブラリ作者 だけのものではありません。たとえば console.log 風の log 関数を作るときや、 配列を返す API のような関数で重宝します。次は min と max を可変長で求める例です。
JavaScript
const minOf = (...nums) => Math.min(...nums);
const maxOf = (...nums) => Math.max(...nums);
console.log(minOf(3, 7, 1, 9)); // 1
console.log(maxOf(3, 7, 1, 9)); // 9Math.min Math.max はもともと可変長を受け取りますが、配列を直接渡すと NaN になってしまうため、残余引数 + スプレッド構文の組み合わせで 配列 ↔ 引数列 を行き来できるようにしておくと便利です。
やってみよう
残余引数を使って sum を作りましょう。任意の個数の数値を引数で受け取り、その合計を return します。引数 0 個のときは 0 を返してください。 reduce を使うと 1 行で書けますが、 for ループでも構いません。
よくある質問
Q. スプレッド構文の典型的な使い道は?
A. 配列・オブジェクトのコピー([...arr]、{...obj})、結合([...a, ...b])、関数引数の展開(fn(...args))が代表例です。深いコピーはできない点に注意し、ネスト構造を完全複製したいときは structuredClone(obj) を使ってください。
Q. スプレッドとレストの違いは?
A. 見た目は ... で同じですが、配列を展開するのがスプレッド、引数を集めるのがレスト(残余引数)です。function fn(...args) のように関数定義側で使うとレスト、fn(...arr) のように呼び出し側で使うとスプレッドになります。
Q. オブジェクトを展開するときの上書き優先順位は?
A. { ...a, ...b } と書くと b のキーが a を上書きします。デフォルト値を先に展開し、ユーザー設定を後ろで上書きする { ...defaults, ...userOpts } が定番イディオムです。順序を間違えるとデフォルト値が勝ってしまうので注意してください。
次のレッスン
次は コールバック関数 で、...args で任意の数の引数を配列として受け取る を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 残余引数 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 残余引数 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- ...nums の残余引数で引数を受け取る
- 受け取った数値の合計を return する
- 引数 0 個のときは 0 を返す
入出力例
test-cases.txt
sum() → 0
sum(1, 2, 3) → 6
sum(10, 20, 30, 40) → 100
sum(-1, 1) → 0