JavaScriptのスプレッド構文(Spread Syntax)完全ガイド

javascript spread syntax JavaScript
この記事は約6分で読めます。

この記事の最終更新日: 2025年5月12日

この記事の対象読者

  • JavaScript を学び始めた初学者〜中級者
  • React/Vue などで状態管理やイミュータブルな操作を理解したい方
  • 可読性を重視したモダン JavaScript コーディングを目指す方
javascript spread syntax

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 文字ずつ
Setconst 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. よくある落とし穴・パフォーマンス

  1. 浅いコピー問題:ネストの深いデータ構造では副作用に注意。
  2. 順序と上書き:オブジェクト展開は 右側優先。意図しない上書きを招きやすい。
  3. 大量データ展開のオーバーヘッド:巨大配列を展開 → 関数呼び出しするとスタックサイズ超過のリスクも。
  4. イテレータを 2 回消費:スプレッドはイテレータを一度で消費するので再利用できない。

7. 対応ブラウザ・トランスパイル

環境配列 Spreadオブジェクト Spread
Chrome46+60+
Firefox16+55+
Safari10+11.1+
Node.js5+8.3+

旧環境向けには Babel などで @babel/plugin-proposal-object-rest-spread を利用すると ES5 に変換可能。


8. まとめ & ベストプラクティス

  • まずはスプレッドでシンプルに書けないか考えるconcatObject.assign より読みやすい。
  • イミュータブル更新の基本兵器:React の useState や Redux のリデューサでは不可欠。
  • ネストが深い場合は深いコピーのコストを意識:パフォーマンスとメモリを天秤に。
  • 右側優先のルールを頭に入れる:設定値マージ時の予期せぬ上書きを防止。

スプレッド構文をマスターすると、JavaScript の「配列・オブジェクト操作」が劇的に読みやすくなります。ぜひ日々のコーディングで積極的に活用し、一段上の可読性を手に入れましょう。


参考リンク

コメント

タイトルとURLをコピーしました