3秒でわかる
配列やオブジェクトの中身を1段ばらして書き出すJavaScriptの記法。元の値を壊さずにコピーや結合を作るときに使います。
もう少し詳しく
どういうものか
スプレッド構文は、点を3つ並べて配列やオブジェクトの中身をその場に展開する記法です。[...arr] と書くと arr の要素を並べた新しい配列ができ、{...obj} と書くとキーと値を並べた新しいオブジェクトができます。展開した後ろに要素を足せば追加、同じキーを後ろに書けば上書きになります。
なぜ必要か
配列やオブジェクトを変数に代入しても、コピーではなく同じ実体を指すだけです。push で要素を足すと、参照しているすべての場所で中身が変わります。Reactの状態のように「変わったかどうか」を参照の一致で判定する仕組みでは、中身を直接書き換えると変化に気づいてもらえず画面が更新されません。新しい入れ物を作って渡すために、この記法が要ります。元の値を残したまま次の状態を作れるので、変更前と変更後を並べて比べる処理も書きやすくなります。
具体例
const base = [1, 2, 3];
const added = [...base, 4]; // base は 1,2,3 のまま
const merged = [...base, ...added];
const user = { id: 1, name: "yuki", tags: ["a"] };
const renamed = { ...user, name: "sora" }; // name だけ差し替え
// <a href="/glossary/function" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">関数</a>呼び出しでも展開できる
console.log(Math.max(...base)); // 3
// 残りをまとめて受け取る側は rest と呼ぶ
const [head, ...rest] = merged;つまずきやすいところ
コピーされるのは1段目だけです。上の renamed.tags は user.tags と同じ配列を指しているため、片方に push すると両方に反映されます。入れ子を含む値を安全に複製したいなら、階層ごとに展開するか structuredClone を使います。もうひとつ、同じキーを書いたときは後ろが勝ちます。既定値を入れたいなら既定値を先に、上書き値を後ろに置きます。
似た用語との違い
| 記法 | 向き |
|---|---|
| スプレッド構文 | まとまりをばらして書き出す |
| レスト構文 | 余った値をひとつにまとめて受け取る |
| 分割代入 | 中身を取り出して変数へ割り当てる |
覚え方
中身を1段だけ外へ出す記号だと捉えます。だから入れ子の中までは新しくならない、という制限も同じ理解から説明できます。
浅いコピー、という言い方も同じことを指しています。配列とオブジェクトのどちらでも、書き方はまったく同じです。