スプレッド構文と残余 — ... の2つの意味

同じ ... が、広げる側と集める側で逆の意味になります。配列・オブジェクト・関数それぞれの使い方、後ろ勝ちの上書き、複製が1段しか効かない点までを実行して確かめます。

実行して検証済み処理系Node 22.22.3対応ES2018難易度●●○○○目安8更新

... には2つの意味があります。置く場所で決まります。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2, 3 ] 1 [ 2, 3 ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2, 3 ] [ 0, 1, 2 ] [ 1, 2, 1, 2 ] 5
  • 右辺(値を作る側)… 広げる(スプレッド)
  • 左辺(受け取る側)… 集める(残余)

同じ記号で、逆の働きです。

配列を広げる

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 'あ', 'い' ] [ 1, 2 ] [ [ 'a', 1 ] ]
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
{ a: 1, b: 2 } { a: 2 } { a: 2 } { a: 1 }

関数の引数としても広げられます。 Math.max() は配列を受け取らないので、 ... で1つずつに開いてから渡します。

要素が非常に多いと、引数の上限に当たることがあります。件数が読めないときは reduce() を使ってください。

文字列も広げられる

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
{ retry: 1, timeout: 50 } { retry: 1, timeout: 1000 }
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
{ a: 1 }

広げられるのは反復可能なものです。配列・文字列・SetMap が該当します。

文字列は符号位置ごとに分かれるので、絵文字が割れません。 → 文字を正しく数える

オブジェクトを広げる

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
{ '0': 1, '1': 2 }
example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1 [ 2, 3 ] 1 { b: 2, c: 3 }

同じ鍵があれば後ろが勝ちます 既定値を先に、上書きを後ろに置く、という順で書きます。

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
6 0
javascript
const original = { x: { y: 1 } };
const copied = { ...original };

copied.x.y = 99;

console.log(original.x.y);
99

nullundefined を広げても落ちません

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
1 99
javascript
function wrong(...rest, last) {}

Object.keys(null) は落ちるのに、こちらは落ちません。 この差が、原因の切り分けを難しくします。 → TypeError: Cannot convert undefined or null to object

配列をオブジェクトに広げると

example.js
出力書き換えて実行できます
Ctrl+Enter でも実行JS · UTF-8
[ 1, 2, 3 ]

添字が鍵になります。 意図してやることは、まずありません。 配列を渡すつもりでオブジェクトに広げていないか確かめてください。

集める側

分割代入で

残りをまとめて受け取れます。 鍵を1つ除いたオブジェクトを作るのに、いちばん短い書き方です。 → オブジェクトから必要な鍵だけ取り出す・除く

関数の引数で

渡されなければ空配列です。 → 関数の引数 — 既定値・可変長・分割代入

いちばんの落とし穴:1段しか複製されない

copied は新しいオブジェクトですが、x は同じものを指しています。 これを浅いコピーと呼びます。

深く複製するなら structuredClone() です。

オブジェクトを結合する

よくある間違い

関数の途中に残余を書く

残余引数は最後にしか置けません

これは構文として読めません。実行する前に弾かれます。 構文の誤りなので、このページでは実行例にできません。

push の代わりに使って遅くする

結果は正しいのですが、毎回すべてを作り直しています。 件数が増えると急に遅くなります。

繰り返しの中で増やすなら push() を使ってください。 → push() / pop() / shift() / unshift()

まとめ

  • 同じ ... が、右辺では広げ、左辺では集める
  • 広げられるのは反復可能なもの(配列・文字列・SetMap
  • オブジェクトは後ろが勝つ。既定値を先に書く
  • null / undefined を広げても落ちない
  • 配列をオブジェクトに広げると添字が鍵になる
  • 複製は1段だけ。 深く複製するなら structuredClone()
  • 繰り返しの中で [...items, n] を使わない

この記事の根拠

  1. Spread — ECMAScript® 2026 Language Specificationtc39.es
  2. Rest Parameters — ECMAScript® 2026 Language Specificationtc39.es
  3. スプレッド構文 — MDNdeveloper.mozilla.org

掲載しているコード例は、公開前に読み手が押したときに動くのと同じもので実行して出力を突き合わせています。結果はリポジトリに残しています。

このページの原文(Markdown)