スプレッド構文(...)
『JavaScript』におけるスプレッド構文の基本構文です。ES2015(ES6)で導入された『...』演算子を使うと、配列やオブジェクトの要素を展開して別の場所に展開できます。配列のコピー・結合・関数への引数展開、オブジェクトのシャローコピーとプロパティの上書きなど、実務で頻繁に使うパターンを押さえておくことが重要です。また、見た目が似ている分割代入のrestパラメータとの違いも理解しておきましょう。
構文
// 配列の展開(関数の引数に展開)
関数名(...配列);
// 配列リテラル内での展開(コピー・結合)
const コピー = [...元の配列];
const 結合 = [...配列1, ...配列2];
// オブジェクトリテラル内での展開(シャローコピー・上書き)
const コピー = { ...元のオブジェクト };
const 上書き = { ...元のオブジェクト, プロパティ名: 新しい値 };
配列への使い方
| パターン | 概要 |
|---|---|
| [...配列] | 配列のシャローコピーを作ります。元の配列に影響を与えずに操作できます。 |
| [...配列1, ...配列2] | 2つ以上の配列を結合した新しい配列を作ります。『concat()』と同等の処理をより直感的に書けます。 |
| [要素, ...配列] | 配列の先頭に新しい要素を追加した新しい配列を作ります。元の配列は変更されません。 |
| 関数名(...配列) | 配列の各要素を関数の引数として順番に渡します。従来の『apply()』の代替として使えます。 |
| Math.max(...配列) | 数値の配列から最大値を求める典型的な使い方です。 |
オブジェクトへの使い方
| パターン | 概要 |
|---|---|
| { ...オブジェクト } | オブジェクトのシャローコピーを作ります。ネストしたオブジェクトは参照が共有されます。 |
| { ...オブジェクト, key: 値 } | コピーしながら特定のプロパティを上書きします。後に書いたプロパティが優先されます。 |
| { ...オブジェクト1, ...オブジェクト2 } | 2つのオブジェクトをマージします。同名のプロパティは後に書いた方で上書きされます。 |
| { デフォルト値, ...受け取ったオブジェクト } | デフォルト値を先に書き、後からスプレッドで上書きするパターンです。設定オブジェクトのマージによく使われます。 |
スプレッド構文とrestパラメータの違い
| 項目 | スプレッド構文(...) | restパラメータ(...) |
|---|---|---|
| 使う場所 | 配列リテラル・オブジェクトリテラル・関数の呼び出し側で使います。 | 関数の定義側(引数リスト)で使います。 |
| 動作 | 配列・オブジェクトを展開(分解)します。 | 複数の引数をひとつの配列にまとめます。 |
| 例 | 『関数名(...配列)』で配列の各要素を引数として渡します。 | 『function 関数名(...args)』で残りの引数すべてを配列として受け取ります。 |
| 記憶のコツ | 「展開する」側です。1つのものを複数に広げます。 | 「集める」側です。複数のものを1つにまとめます。 |
サンプルコード
spread_array.js
// 呪術廻戦: 配列のコピー・結合・引数展開を確認します。
const gradeOneJujutsushi = ["五条悟", "夏油傑", "乙骨憂太"];
const gradeZeroJujutsushi = ["両面宿儺"];
// シャローコピー: 元の配列を変更せずに操作できます。
const copyOfGradeOne = [...gradeOneJujutsushi];
copyOfGradeOne.push("九十九由基");
console.log("元の配列: " + gradeOneJujutsushi);
console.log("コピー後: " + copyOfGradeOne);
// 結合: 2つの配列を新しい配列にまとめます。
const allTopJujutsushi = [...gradeZeroJujutsushi, ...gradeOneJujutsushi];
console.log("---");
console.log("全TOP: " + allTopJujutsushi);
// 先頭・末尾への要素追加
const withNewMember = ["日下部篤也", ...gradeOneJujutsushi, "庵歌姫"];
console.log("拡張後: " + withNewMember);
// 引数への展開: Math.max に配列の各要素を渡します。
const cursedEnergyLevels = [9000, 8500, 7200, 9800, 6000];
const maxEnergy = Math.max(...cursedEnergyLevels);
console.log("---");
console.log("最大呪力: " + maxEnergy);
実行結果
$ node spread_array.js 元の配列: 五条悟,夏油傑,乙骨憂太 コピー後: 五条悟,夏油傑,乙骨憂太,九十九由基 --- 全TOP: 両面宿儺,五条悟,夏油傑,乙骨憂太 拡張後: 日下部篤也,五条悟,夏油傑,乙骨憂太,庵歌姫 --- 最大呪力: 9800
spread_object.js
// 呪術廻戦: オブジェクトのコピー・マージ・プロパティ上書きを確認します。
const itadori = {
name: "虎杖悠仁",
grade: "1級",
technique: "発勁",
cursedEnergy: 8500,
};
// シャローコピー: 新しいオブジェクトを作ります。元のオブジェクトは変更されません。
const itadoriCopy = { ...itadori };
itadoriCopy.cursedEnergy = 9000; // コピーのみ変更します。
console.log("元のオブジェクト呪力: " + itadori.cursedEnergy);
console.log("コピーの呪力: " + itadoriCopy.cursedEnergy);
// プロパティの上書き: 後に書いたプロパティが優先されます。
const upgradedItadori = {
...itadori,
grade: "特級", // gradeを上書きします。
technique: "逆順環境", // techniqueを上書きします。
};
console.log("---");
console.log("等級: " + upgradedItadori.grade);
console.log("術式: " + upgradedItadori.technique);
console.log("名前: " + upgradedItadori.name); // 上書きしていない値はそのまま引き継がれます。
// 2つのオブジェクトをマージします。
const baseStats = { hp: 100, speed: 80 };
const cursedStats = { cursedEnergy: 8500, technique: "発勁" };
const fullStats = { ...baseStats, ...cursedStats };
console.log("---");
console.log("フルステータス:", fullStats);
実行結果
$ node spread_object.js
元のオブジェクト呪力: 8500
コピーの呪力: 9000
---
等級: 特級
術式: 逆順環境
名前: 虎杖悠仁
---
フルステータス: { hp: 100, speed: 80, cursedEnergy: 8500, technique: '発勁' }
spread_vs_rest.js
// 呪術廻戦: スプレッド構文とrestパラメータの違いを確認します。
// 見た目は同じ「...」ですが、使う場所と動作が異なります。
// --- restパラメータ(関数定義側) ---
// 複数の引数を1つの配列にまとめて受け取ります。
function showJujutsushiList(leader, ...members) {
console.log("リーダー: " + leader);
console.log("メンバー: " + members.join("、"));
}
// --- スプレッド構文(関数呼び出し側) ---
// 配列の各要素を引数として展開して渡します。
const team = ["五条悟", "虎杖悠仁", "伏黒恵", "釘崎野薔薇"];
showJujutsushiList(...team); // teamの各要素が引数に展開されます。
console.log("---");
// 組み合わせの例: 先頭を別処理し、残りをまとめて展開します。
const specialGradeList = ["両面宿儺", "九十九由基", "夏油傑", "五条悟"];
// restパラメータで残り全部をひとまとめにします。
function processSpecialGrade(strongest, ...rest) {
console.log("最強: " + strongest);
console.log("他の特級術師: " + rest.join("、"));
// スプレッド構文でさらに別の配列と結合します。
const extendedList = [...rest, "乙骨憂太"];
console.log("リスト拡張後: " + extendedList.join("、"));
}
processSpecialGrade(...specialGradeList);
実行結果
$ node spread_vs_rest.js リーダー: 五条悟 メンバー: 虎杖悠仁、伏黒恵、釘崎野薔薇 --- 最強: 両面宿儺 他の特級術師: 九十九由基、夏油傑、五条悟 リスト拡張後: 九十九由基、夏油傑、五条悟、乙骨憂太
spread_shallow_copy.js
// 呪術廻戦: シャローコピーの注意点を確認します。
// スプレッド構文によるコピーは「シャローコピー(浅いコピー)」です。
// ネストしたオブジェクト・配列は参照が共有されます。
const gojo = {
name: "五条悟",
grade: "特級",
techniques: {
primary: "無限",
domain: "無量空処",
},
};
// シャローコピーを作ります。
const gojoCopy = { ...gojo };
// トップレベルのプロパティは独立しています(コピー先を変更しても元に影響しません)。
gojoCopy.grade = "最強";
console.log("元のgrade: " + gojo.grade); // 変更されません。
console.log("コピーのgrade: " + gojoCopy.grade);
// ネストしたオブジェクトは参照が共有されています(同じオブジェクトを指しています)。
gojoCopy.techniques.domain = "紫(改)";
console.log("---");
console.log("元のdomain: " + gojo.techniques.domain); // 影響を受けます!
console.log("コピーのdomain: " + gojoCopy.techniques.domain);
// 完全なディープコピーが必要な場合はJSON.parseとJSON.stringifyを使う方法があります。
// (ただし関数やundefinedは失われる点に注意が必要です)
const gojoDeepCopy = JSON.parse(JSON.stringify(gojo));
gojoDeepCopy.techniques.domain = "無量空処(完全版)";
console.log("---");
console.log("元のdomain(ディープコピー後): " + gojo.techniques.domain); // 影響を受けません。
実行結果
$ node spread_shallow_copy.js 元のgrade: 特級 コピーのgrade: 最強 --- 元のdomain: 紫(改) コピーのdomain: 紫(改) --- 元のdomain(ディープコピー後): 紫(改)
概要
スプレッド構文(『...』)は、配列やオブジェクトの要素を別の場所に展開する構文です。配列では『[...元の配列]』でコピー、『[...配列1, ...配列2]』で結合、『関数名(...配列)』で引数への展開が行えます。オブジェクトでは『{ ...元のオブジェクト }』でコピー、『{ ...元のオブジェクト, key: 新しい値 }』でプロパティの上書きができます。後に書いたプロパティが優先されるため、デフォルト値のマージパターンにもよく使われます。
スプレッド構文によるコピーはシャローコピー(浅いコピー)です。トップレベルのプロパティは独立したコピーになりますが、ネストしたオブジェクトや配列は参照が共有されます。ネストした部分も含めた完全なコピー(ディープコピー)が必要な場合は、『JSON.parse(JSON.stringify(obj))』などの別の方法を検討してください(ただし関数や『undefined』のプロパティは失われます)。
見た目が同じ『...』でも、スプレッド構文と分割代入のrestパラメータは役割が逆です。スプレッド構文は「展開する」(関数呼び出し側・配列・オブジェクトリテラル内で使う)、restパラメータは「集める」(関数定義側の引数リストで使う)と覚えておくとわかりやすいです。スプレッド構文はES2015以降の機能で、IE は非対応です。オブジェクトへのスプレッド(『{ ...obj }』)はES2018で導入されたため、対応環境に注意してください。
対応ブラウザ
3 以前 ×
Android Browser
67 以降 ○
4 以前 ×
Chrome Android
46 以降 ○
17 以前 ×
Firefox Android
36 以降 ○
3 以前 ×記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。