はじめに
スプレッド構文は、JavaScriptで配列やオブジェクトを展開するための記法です。...という3つのドット記号を使って表現します。
この構文を使うと、配列のコピーや結合、オブジェクトのマージなどが簡潔に書けるようになります。ES2015(ES6)で配列に、ES2018でオブジェクトに導入されました。
この記事では、スプレッド構文の基本的な使い方を、実際のコード例とともに解説していきます。
スプレッド構文の基本
スプレッド構文は、配列やオブジェクトの要素を展開して、個別の要素として扱えるようにします。基本的な書き方は以下の通りです。
const array = [1, 2, 3];
console.log(...array); // 1 2 3
...arrayと書くことで、配列の中身が展開され、1, 2, 3という個別の値として扱われます。
スプレッド構文が使えるのは主に以下のデータ型です。
- 配列(Array)
- オブジェクト(Object)
- 文字列(String)
- その他の反復可能なオブジェクト
それでは、具体的な使い方を見ていきましょう。
配列でのスプレッド構文
配列のコピー
従来の方法では、配列をコピーするときにslice()メソッドなどを使っていました。スプレッド構文を使うと、より直感的に書けます。
// 従来の方法
const original = [1, 2, 3];
const copy1 = original.slice();
// スプレッド構文を使った方法
const copy2 = [...original];
console.log(copy2); // [1, 2, 3]
配列の結合
複数の配列を結合する場合も、スプレッド構文を使うとシンプルに書けますね。
// 従来の方法
const arr1 = [1, 2];
const arr2 = [3, 4];
const combined1 = arr1.concat(arr2);
// スプレッド構文を使った方法
const combined2 = [...arr1, ...arr2];
console.log(combined2); // [1, 2, 3, 4]
配列に要素を追加
配列の先頭や末尾、途中に要素を追加する場合も便利です。
const numbers = [2, 3, 4];
// 先頭に追加
const withFirst = [1, ...numbers];
console.log(withFirst); // [1, 2, 3, 4]
// 末尾に追加
const withLast = [...numbers, 5];
console.log(withLast); // [2, 3, 4, 5]
// 途中に追加
const withMiddle = [1, ...numbers, 5, 6];
console.log(withMiddle); // [1, 2, 3, 4, 5, 6]
配列の操作がこのように柔軟にできるのは便利ですね。処理の流れを図で表すと以下のようになります。
オブジェクトでのスプレッド構文
オブジェクトのコピー
配列と同様に、オブジェクトもスプレッド構文でコピーできます。
const user = {
name: '太郎',
age: 25
};
const userCopy = { ...user };
console.log(userCopy); // { name: '太郎', age: 25 }
オブジェクトのマージ
複数のオブジェクトを結合する場合も、スプレッド構文が使えます。
const basic = {
name: '太郎',
age: 25
};
const contact = {
email: 'taro@example.com',
phone: '090-1234-5678'
};
const fullProfile = { ...basic, ...contact };
console.log(fullProfile);
// {
// name: '太郎',
// age: 25,
// email: 'taro@example.com',
// phone: '090-1234-5678'
// }
プロパティの上書き
同じキーのプロパティがある場合、後から指定したものが優先されます。
const user = {
name: '太郎',
age: 25,
city: '東京'
};
const updated = {
...user,
age: 26,
city: '大阪'
};
console.log(updated);
// {
// name: '太郎',
// age: 26,
// city: '大阪'
// }
この上書きの仕組みを図で表すと以下のようになります。
関数の引数でのスプレッド構文
配列を個別の引数に展開
配列の要素を、関数の個別の引数として渡すことができます。
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
// 従来の方法
const result1 = sum(numbers[0], numbers[1], numbers[2]);
// スプレッド構文を使った方法
const result2 = sum(...numbers);
console.log(result2); // 6
Math.maxなどでの活用例
配列の中から最大値や最小値を取得する場合に便利です。Math.max()やMath.min()は個別の引数を受け取る関数なので、スプレッド構文と相性が良いです。
const scores = [85, 92, 78, 95, 88];
const maxScore = Math.max(...scores);
const minScore = Math.min(...scores);
console.log(maxScore); // 95
console.log(minScore); // 78
関数呼び出しの流れを図で表してみましょう。
注意点
コピーは浅いコピー(シャローコピー)であること
スプレッド構文でのコピーは、浅いコピーです。つまり、ネストした配列やオブジェクトの中身は参照がコピーされるだけで、実体は共有されます。
const original = {
name: '太郎',
address: {
city: '東京',
prefecture: '東京都'
}
};
const copied = { ...original };
// ネストしたオブジェクトを変更すると
copied.address.city = '大阪';
// 元のオブジェクトも影響を受ける
console.log(original.address.city); // '大阪'
ネストしたデータの扱い
ネストしたデータを完全にコピーしたい場合は、各階層でスプレッド構文を使う必要があります。
const original = {
name: '太郎',
address: {
city: '東京',
prefecture: '東京都'
}
};
// ネストした部分もコピー
const copied = {
...original,
address: { ...original.address }
};
copied.address.city = '大阪';
console.log(original.address.city); // '東京'(影響を受けない)
console.log(copied.address.city); // '大阪'
シャローコピーとディープコピーの違いを図で示します。
まとめ
スプレッド構文を使うことで、以下のようなメリットがあります。
コードが簡潔になる
従来のconcat()やslice()などのメソッドを使うよりも、直感的で読みやすいコードが書けます。
柔軟な操作が可能
配列やオブジェクトの結合、コピー、要素の追加など、様々な操作を統一的な記法で実現できます。
イミュータブルな処理
元のデータを変更せずに、新しいデータを作成できるため、予期しない副作用を防げます。
覚えておきたい基本パターンは以下の3つです。
- 配列のコピーと結合:
[...array]、[...arr1, ...arr2] - オブジェクトのコピーとマージ:
{ ...obj }、{ ...obj1, ...obj2 } - 関数の引数に展開:
func(...array)
スプレッド構文は、最初は慣れないかもしれませんが、使いこなせるようになると、JavaScriptのコードがより読みやすく、保守しやすくなります。まずは配列のコピーや結合から試してみてください。