この記事の最終更新日: 2025年5月12日
この記事の対象読者
- JavaScript を学び始めた初学者〜中級者
- React/Vue などで状態管理やイミュータブルな操作を理解したい方
- 可読性を重視したモダン JavaScript コーディングを目指す方

0. スプレッド構文とは?
スプレッド構文(...)は 配列・オブジェクト・その他イテラブルな値を 展開 する記法 です。「展開」とは、要素を 1 つずつ取り出してリテラルの中に ばら撒く イメージ。ES2015(配列)と ES2018(オブジェクト)で導入され、短く読みやすいコード が書けるようになりました。
スプレッドとレストの違い
...が 右辺(展開される側)にあれば スプレッド(要素をばらす)。...が 左辺(受け取る側)にあれば レスト(残余をまとめる)。const arr = [1, 2, 3]; const [first, ...rest] = arr; // ← レスト構文 const clone = [...arr]; // ← スプレッド構文
1. 配列での活用パターン
1‑1. 配列を連結する
const arr1 = ["apple", "banana"];
const arr2 = ["grape", "peach"];
// 従来:concat
const mixed1 = arr1.concat(arr2);
// スプレッド
const mixed2 = [...arr1, ...arr2];
- 可読性が高い:どの順番で結合しているか一目でわかる。
- ネスト不要:複数配列をさらに追加するときも
concatチェーンよりシンプル。
1‑2. シャローコピー(浅い複製)
const original = [1, 2, 3];
const copy = [...original];
- = 代入との違い:参照ではなく新しい配列が生成。
- 注意:ネストした配列やオブジェクト内部は 参照が共有 されるので深いコピーではない。
1‑3. イテラブル → 配列に変換
DOM から得た NodeList や文字列を配列化する際にも便利。
[...document.querySelectorAll("a")].forEach(a => a.classList.add("link"));
const chars = [..."hello"];
// => ["h","e","l","l","o"]
1‑4. Array メソッド引数に展開
const nums = [3, 5, 7];
console.log(Math.max(...nums)); // 7
2. 関数呼び出しでの展開
2‑1. apply の置き換え
function sum(a, b, c) { return a + b + c; }
const values = [1, 2, 3];
// 旧来
sum.apply(null, values);
// スプレッド
sum(...values);
2‑2. 可変長引数との組み合わせ
function average(...nums) {
return nums.reduce((acc, v) => acc + v) / nums.length;
}
const scores = [80, 90, 100];
console.log(average(...scores));
3. オブジェクトでの活用パターン
3‑1. オブジェクトのマージ
const user = { id: 1, name: "Alice" };
const meta = { loggedIn: true };
const profile = { ...user, ...meta };
// { id: 1, name: "Alice", loggedIn: true }
- 後勝ち:同じキーが存在すると右側の値で上書き。
3‑2. 部分的に値を更新する
const state = { count: 0 };
// Redux などイミュータブル更新
const next = { ...state, count: state.count + 1 };
3‑3. オブジェクトのコピーとネストの罠
const nested = { user: { name: "Bob" } };
const shallow = { ...nested };
shallow.user.name = "Eve";
console.log(nested.user.name); // "Eve" (参照共有!)
- 深いコピー が必要なら
structuredCloneやライブラリ(lodash_.cloneDeep等)を検討。
4. その他イテラブルとの連携
| データ型 | 例 | 備考 |
|---|---|---|
| 文字列 | [...'abc'] → ['a','b','c'] | UTF‑16 サロゲートペアも 1 文字ずつ |
| Set | const unique = [...new Set(arr)] | 重複排除に便利 |
| Map (キー値タプル) | [...map] | [key, value] の配列に展開 |
| Generator | [...gen()] | 非同期ジェネレータには使えない |
5. 実務で役立つレシピ集
5‑1. 重複しない配列を作る
const arr = [1,2,2,3];
const uniq = [...new Set(arr)]; // [1,2,3]
5‑2. オブジェクト配列を条件付きでマージ
const defaultOpts = { secure: true, retries: 3 };
function request(url, opts = {}) {
const config = { ...defaultOpts, ...opts };
// fetch(url, config) ...
}
5‑3. 配列末尾以外にも挿入
const arr = [1,4];
const extended = [1,2,3, ...arr.slice(1)]; // [1,2,3,4]
6. よくある落とし穴・パフォーマンス
- 浅いコピー問題:ネストの深いデータ構造では副作用に注意。
- 順序と上書き:オブジェクト展開は 右側優先。意図しない上書きを招きやすい。
- 大量データ展開のオーバーヘッド:巨大配列を展開 → 関数呼び出しするとスタックサイズ超過のリスクも。
- イテレータを 2 回消費:スプレッドはイテレータを一度で消費するので再利用できない。
7. 対応ブラウザ・トランスパイル
| 環境 | 配列 Spread | オブジェクト Spread |
|---|---|---|
| Chrome | 46+ | 60+ |
| Firefox | 16+ | 55+ |
| Safari | 10+ | 11.1+ |
| Node.js | 5+ | 8.3+ |
旧環境向けには Babel などで
@babel/plugin-proposal-object-rest-spreadを利用すると ES5 に変換可能。
8. まとめ & ベストプラクティス
- まずはスプレッドでシンプルに書けないか考える:
concatやObject.assignより読みやすい。 - イミュータブル更新の基本兵器:React の
useStateや Redux のリデューサでは不可欠。 - ネストが深い場合は深いコピーのコストを意識:パフォーマンスとメモリを天秤に。
- 右側優先のルールを頭に入れる:設定値マージ時の予期せぬ上書きを防止。
スプレッド構文をマスターすると、JavaScript の「配列・オブジェクト操作」が劇的に読みやすくなります。ぜひ日々のコーディングで積極的に活用し、一段上の可読性を手に入れましょう。
参考リンク

大阪のエンジニアが書いているブログ。



コメント