スプレッド構文と「旧構文」をざっくり比較すると
ES6 のスプレッド構文 ... は、
「配列やオブジェクトの中身をその場でバラして並べる」ための新しい書き方です。
旧構文(ES5 まで)は、concat / slice / push / Object.assign / apply などを組み合わせて同じことをしていました。
ここが重要です:
- できることはほぼ同じでも、スプレッド構文の方が「意図が読みやすい」「バグを生みにくい」
- 旧構文は「何をしたいのか」を頭の中で変換しないと理解しづらい
まずは、「旧構文でやっていたことを、スプレッド構文でどう書き換えるか」を見ていきます。
配列の結合:concat vs スプレッド
ES5 の書き方(concat)
var a = [1, 2];
var b = [3, 4];
var merged = a.concat(b);
console.log(merged); // [1, 2, 3, 4]
JavaScript何をしているか分かるものの、a.concat(b) から「a のあとに b をくっつけて新しい配列を作っている」と一瞬変換が必要です。
ES6 の書き方(スプレッド)
const a = [1, 2];
const b = [3, 4];
const merged = [...a, ...b];
console.log(merged); // [1, 2, 3, 4]
JavaScript[...a, ...b] は、そのまま「a の中身、そのあと b の中身」と読めます。
ここが重要です:「どの配列がどの順番で並ぶか」が見た目そのまま になっていること。
真ん中に値を挟むのも、スプレッドの方が直感的です。
// ES5
var merged = a.concat([99]).concat(b);
// ES6
const merged2 = [...a, 99, ...b];
JavaScript配列コピー:slice vs スプレッド
ES5 の書き方(slice)
var arr = [1, 2, 3];
var copy = arr.slice(); // 全体コピー
copy[0] = 99;
console.log(arr); // [1, 2, 3]
console.log(copy); // [99, 2, 3]
JavaScriptslice() 本来の意味は「一部を切り出す」ですが、
「引数なしで呼ぶとコピーになる」という“お約束”を知っていないと読みづらいです。
ES6 の書き方(スプレッド)
const arr = [1, 2, 3];
const copy = [...arr];
copy[0] = 99;
console.log(arr); // [1, 2, 3]
console.log(copy); // [99, 2, 3]
JavaScript[...arr] は、“中身をバラして新しい配列に入れ直している”ことがそのまま見えるので、
「これはコピーだな」と直感的に理解できます。
ここが重要です:
スプレッドを覚えておくと、「concat / slice / push などの“裏技”的な使い方」を暗記しなくてよくなります。
関数引数展開:apply vs スプレッド
ES5 の書き方(apply)
配列を「複数の引数」として渡したいとき、 ES5 では apply を使うのが定番でした。
var nums = [5, 2, 9];
var max = Math.max.apply(null, nums);
console.log(max); // 9
JavaScriptapply(null, nums) の意味を知らないと、「なぜ null?」「なぜ配列がここに?」と戸惑います。
ES6 の書き方(スプレッド)
const nums = [5, 2, 9];
const max = Math.max(...nums);
console.log(max); // 9
JavaScriptMath.max(...nums) は、「nums の中身をバラして渡している」と読めます。
自作関数でも同じです。
// ES5
function sum3(a, b, c) {
return a + b + c;
}
var arr = [10, 20, 30];
console.log(sum3.apply(null, arr));
// ES6
const sum3 = (a, b, c) => a + b + c;
const arr2 = [10, 20, 30];
console.log(sum3(...arr2));
JavaScriptここが重要です:
「配列をそのまま渡したい」のか、「配列の中身を引数として渡したい」のかが ... の有無だけで明確になる 点です。
オブジェクトのマージ:Object.assign vs スプレッド
ES5 の書き方(Object.assign)
オブジェクトをマージする標準的な方法は Object.assign でした。
var base = { theme: "light", lang: "ja" };
var extra = { lang: "en", debug: true };
var merged = Object.assign({}, base, extra);
console.log(merged);
// { theme: "light", lang: "en", debug: true }
JavaScriptObject.assign({}, base, extra) は、
- 空オブジェクト
{}に - base の中身をコピーして
- さらに extra の中身で上書き
を意味しますが、それを一瞬で読み取るには慣れが必要です。
ES6 の書き方(スプレッド)
const base = { theme: "light", lang: "ja" };
const extra = { lang: "en", debug: true };
const merged = { ...base, ...extra };
console.log(merged);
// { theme: "light", lang: "en", debug: true }
JavaScript{ ...base, ...extra } は、base の中身を書き出して、その後に extra の中身を書き出す、という意味になります。
ここが重要です:
Object.assignは「関数呼び出しの知識」が必要- スプレッドは「中身を貼り付けている」イメージで、構造から自然に読める
さらに、「一部だけ変えた新オブジェクト」を作るのもスプレッドの方が明快です。
// ES5
var config = { theme: "light", lang: "ja", debug: false };
var newConfig = Object.assign({}, config, { debug: true });
// ES6
const config = { theme: "light", lang: "ja", debug: false };
const newConfig = { ...config, debug: true };
JavaScript「元を壊さない」書き方の違い:直接変更 vs スプレッド
ES5 の典型的なミスパターン(直接変更)
var config = { theme: "light", lang: "ja" };
function enableDarkTheme(cfg) {
cfg.theme = "dark"; // 引数を直接書き換え
}
enableDarkTheme(config);
console.log(config.theme); // "dark"(元が変わってしまう)
JavaScriptこのようなコードは、「関数を呼び出すと元のオブジェクトが書き換わる」ので、
バグの原因になりがちです。
ES6+スプレッドでの不変スタイル
const config = { theme: "light", lang: "ja" };
function enableDarkTheme(cfg) {
// 元をいじらず、「新しい設定」を返す
return { ...cfg, theme: "dark" };
}
const newConfig = enableDarkTheme(config);
console.log(config.theme); // "light"
console.log(newConfig.theme); // "dark"
JavaScriptここが重要です:
- ES5 でももちろん「コピーしてから変更する」ことはできますが、書き方がごちゃつきやすい
- スプレッド構文を使うと、「元+変更点→新オブジェクト」という不変スタイルを簡潔に書ける
この差が、コードの安全性と読みやすさに直結します。
スプレッド構文を選ぶべき理由(旧構文との本質的な違い)
機能的には、ほとんどのことが ES5 でもできます。
それでもスプレッド構文を使う価値が高い理由は、次のような点に集約されます。
読みやすさ:
「何をしたいか」が構文の形に現れており、関数呼び出しの知識に頼らなくていい。
// 旧:何してるか一瞬考える
Object.assign({}, base, extra);
// 新:見たまま
{ ...base, ...extra }
JavaScript不変スタイルとの相性:
「元をそのまま」「新しいものを返す」というパターンを自然に書ける。
// 配列
const newArr = [...oldArr, item];
// オブジェクト
const newObj = { ...oldObj, changed: value };
JavaScriptバグの減少:
「コピーしたつもりで同じものを触っていた」などのミスを減らしやすい。
// 参照コピー(危険)
const same = original;
// 浅いコピー(安全性が高い)
const copy = [...original];
const copy2 = { ...original };
JavaScriptまとめると、
ES5 =「知っていればできるけど、意図が隠れやすい」
ES6 スプレッド =「できることは同じでも、意図が見える・安全に書ける」
という違いだと捉えると分かりやすいです。
例題で「旧構文 → スプレッド構文」の変換に慣れる
// 1) 配列結合
// ES5
var a = [1, 2], b = [3, 4];
var mergedOld = a.concat(b);
// ES6
const mergedNew = [...a, ...b];
// 2) 配列コピー
// ES5
var nums = [1, 2, 3];
var copyOld = nums.slice();
// ES6
const copyNew = [...nums];
// 3) 関数引数展開
// ES5
function sum3(a, b, c) { return a + b + c; }
var arr = [10, 20, 30];
var resultOld = sum3.apply(null, arr);
// ES6
const sum3New = (a, b, c) => a + b + c;
const resultNew = sum3New(...arr);
// 4) オブジェクトマージ
// ES5
var baseCfg = { theme: "light" };
var extraCfg = { debug: true };
var mergedCfgOld = Object.assign({}, baseCfg, extraCfg);
// ES6
const mergedCfgNew = { ...baseCfg, ...extraCfg };
JavaScriptまとめ
スプレッド構文は、旧構文(concat / slice / apply / Object.assign など)でやっていたことを、
- より短く
- より意図が分かりやすく
- より「元を壊さない」スタイルで
書けるようにするための ES6 の強力な武器です。
旧構文を「覚え直す」感覚ではなく、
「昔こう書いてたものを、今はこう書き直せる」 と対応づけて覚えると、
スッと頭に入ってきます。

