関数引数展開とは何か
スプレッド構文の「関数引数展開」は、fn(...array) のように書いて「配列(や配列っぽいもの)をバラして、関数の複数の引数として渡す」書き方です。
ここが重要です:... が「関数呼び出しのカッコの中(右側)」にあるときは、配列展開=要素を1個ずつ引数にする、という意味になります。
const nums = [1, 2, 3];
const sum = (a, b, c) => a + b + c;
console.log(sum(1, 2, 3)); // 6(普通に渡す)
console.log(sum(...nums)); // 6(配列を展開して渡す)
JavaScriptsum(...nums) は、実行時に「sum(1, 2, 3) と同じ」とみなされます。
従来の書き方との違い(apply からの進化)
Math.max / Math.min との組み合わせ
配列の最大値・最小値を取りたいとき、昔は apply を使っていました。
const nums = [5, 2, 9];
console.log(Math.max.apply(null, nums)); // ES5 の書き方
JavaScriptスプレッド構文なら、ここが重要です:Math.max(...nums) のように「見た目そのまま」で書けます。
const nums = [5, 2, 9];
console.log(Math.max(...nums)); // 9
console.log(Math.min(...nums)); // 2
JavaScriptapply に比べて、読みやすさ・書きやすさが圧倒的に良くなります。
自作関数でも同じ感覚で使える
自分で定義した関数にも、そのまま配列を展開して渡せます。
const diff = (a, b, c) => a - b - c;
const args = [10, 3, 2];
console.log(diff(...args)); // 10 - 3 - 2 = 5
JavaScript部分的な引数+スプレッド(固定+可変の混在)
先頭だけ固定、残りは配列から
最初の引数だけ手書きし、残りは配列から展開する、という書き方が自然にできます。
ここが重要です:関数側のシグネチャ(引数リスト)を意識しつつ、「どこを固定し、どこを配列から渡すか」を決める。
const log = (level, a, b, c) => {
console.log(level, a, b, c);
};
const rest = ["A", "B", "C"];
log("INFO", ...rest); // "INFO A B C"
JavaScript可変長のメッセージをまとめて渡す
ログ関数などで、「先頭はレベル、それ以降は可変長引数」というパターンもよくあります。
const logMany = (level, ...messages) => {
console.log(level, ...messages);
};
const msgs = ["start", "user=7", "ok"];
logMany("INFO", ...msgs); // "INFO start user=7 ok"
JavaScriptスプレッド引数と rest パラメータの違い(ここをしっかり)
ここが一番混ざりやすいポイントです。同じ ... でも、立場が逆です。
関数「定義側」の (a, ...rest) は、残りの引数をまとめて受け取る(rest パラメータ)。
関数「呼び出し側」の fn(...array) は、配列をバラして渡す(スプレッド)。
// 定義側:rest パラメータ(受け取る側)
function sumAll(...nums) {
return nums.reduce((s, n) => s + n, 0);
}
// 呼び出し側:スプレッド(渡す側)
const arr = [1, 2, 3];
console.log(sumAll(...arr)); // 6
JavaScriptここが重要です:
- rest は「余りをまとめる(受ける)」
- spread は「配列をバラす(渡す)」
「定義側か/呼び出し側か」で役割が真逆になる、と意識しておくと混乱しません。
実務でよく使うパターン(重要ポイントを深掘り)
既存の関数に配列をそのまま渡したい
既にある API が「可変長引数」を受ける形になっているとき(fn(a, b, c, ...))、配列を渡すにはスプレッドが必須になります。
const nums = [1, 5, 2, 9];
console.log(Math.max(...nums)); // 9
JavaScript配列のまま Math.max(nums) と渡しても、「配列一個」しか引数にならないので動きません。
ここが重要です:「配列の中身を引数として扱いたいとき」は、必ず ... で展開する。
引数リストを動的に組み立てる
条件によって「前後に追加の引数を足したい」ときも、スプレッドで配列をくっつけてから渡せます。
const callApi = (url, ...rest) => {
console.log("url:", url);
console.log("options:", rest);
};
const baseArgs = ["GET", { timeout: 3000 }];
// 先頭に URL を付けて展開
callApi("/users", ...baseArgs);
// 実質 callApi("/users", "GET", { timeout: 3000 })
JavaScript「固定の前後に、可変の真ん中を挟む」ような場合も自然です。
const invoke = (...args) => console.log(...args);
const head = ["INFO"];
const body = ["A", "B"];
const tail = ["done"];
invoke(...head, ...body, ...tail);
// INFO A B done
JavaScriptよくある落とし穴と注意点
配列のまま渡してしまう
fn(arr) と fn(...arr) の違いを意識していないと、想定外の振る舞いになります。
const sum = (a, b, c) => a + b + c;
const nums = [1, 2, 3];
console.log(sum(nums)); // "1,2,3undefinedundefined" に近い変な結果 or NaN
console.log(sum(...nums)); // 6(これが正しい)
JavaScriptここが重要です:関数が「複数の引数」を期待しているのか、「配列1つ」を期待しているのかを、定義を見て判断する。
引数が多すぎ/少なすぎる場合
スプレッドは「配列要素をそのまま順番に引数にする」だけなので、多すぎる引数は無視され、足りない引数は undefined になります。必要なら、関数側で rest パラメータを使ったり、既定値を指定したりして防御します。
const show = (a, b = 0, c = 0) => console.log(a, b, c);
show(...[1, 2, 3, 4]); // 1 2 3(4は捨てられる)
show(...[1]); // 1 0 0(b,c は既定値)
JavaScript「配列ではないもの」を展開しようとしてエラー
スプレッドは「反復可能(iterable)」なものに使えますが、初心者のうちは「とりあえず配列にだけ使う」と意識しておくと安全です。null や undefined に対して ... するとエラーになるので注意してください。
例題で理解を固める
// 1) 最大・最小・合計を計算する関数に配列をそのまま渡したい
const nums = [72, 88, 95, 64];
const max = Math.max(...nums);
const min = Math.min(...nums);
const sum = ((a, b, c, d) => a + b + c + d)(...nums);
console.log(max, min, sum); // 95 64 319
// 2) 自作関数で配列を展開
const greet = (first, middle, last) =>
`Hello, ${first} ${middle} ${last}`;
const nameParts = ["Taro", "J.", "Yamada"];
console.log(greet(...nameParts));
// 3) 固定引数+配列展開
const logWithTag = (tag, ...msgs) => {
console.log(tag, ...msgs);
};
const messages = ["start", "user=7", "ok"];
logWithTag("[APP]", ...messages);
// [APP] start user=7 ok
// 4) 関数ラッパーで引数を追加して渡す
const rawFetch = (...args) => console.log("fetch:", args);
const defaultHeaders = { "X-APP": "demo" };
const myFetch = (url, options = {}) => {
const merged = { ...options, headers: { ...defaultHeaders, ...options.headers } };
rawFetch(url, merged);
};
myFetch("/api", { method: "GET", headers: { "X-USER": "7" } });
JavaScriptまとめ
スプレッド構文の関数引数展開の核心は、「配列(や配列っぽいデータ)をバラして、関数の複数の引数として渡す」ことです。fn(...arr) は fn(arr[0], arr[1], …) という展開。定義側の (...rest) は「まとめて受ける」、呼び出し側の (...array) は「バラして渡す」という役割の違いをしっかり区別してください。最大値・最小値の取得、ログ出力、既存関数への配列入力など、実務で頻出する場面で、スプレッドを使うとシンプルで読みやすい ES6+ コードになります。
