更新日:
【JavaScript】 スプレッド構文について徹底解説!

スプレッド構文は、3つのドット「...」を使って、配列やオブジェクトの要素を展開する記法です。
スプレッド構文の基礎情報
この章では、スプレッド構文の基礎情報について解説します。
スプレッド構文とは
スプレッド構文は、3つのドット...
を使って、配列やオブジェクトの要素を展開したり、新しい配列を作成するための構文です。
以下のように使います。
1
2
const numbers = [1, 2, 3];
console.log(...numbers) //1 2 3
基本的な使い方
この章ではスプレッド構文の基本的な使い方を解説します。
配列のコピー
配列のコピーにはconcat
メソッドがよく使われますが、スプレッド構文を使用してコピーを作成することもできます。
1
2
3
4
5
6
7
8
9
// concatを使ったコピー
const originalArray = [1, 2, [3, 4]];
const copyArray = originalArray.concat();
console.log(copyArray); // 出力: [1, 2, [3, 4]]
// スプレッド構文を使ったコピー
const originalArray = [1, 2, [3, 4]];
const copyArray = [...originalArray];
console.log(copyArray); // 出力: [1, 2, [3, 4]]
配列の結合
配列の結合も同様にconcat
を使って作成するのが一般的でしたが、スプレッド構文を使用しても結合することができます。
1
2
3
4
5
6
7
8
9
10
const numbers1 = [1, 2, 3];
const numbers2 = [4, 5, 6];
// concatを使った結合
const combinedNumbers = numbers1.concat(numbers2);
console.log(combinedNumbers); // [1, 2, 3, 4, 5, 6]
// スプレッド構文を使った結合
const combinedNumbers2 = [...numbers1, ...numbers2];
console.log(combinedNumbers2); // [1, 2, 3, 4, 5, 6]
オブジェクトのコピー
配列だけでなく、オブジェクトもコピーすることができます。
1
2
3
4
const originalObject = { a: 1, b: 2 };
const copyObject = { ...originalObject };
console.log(copyObject); // { a: 1, b: 2 }
オブジェクトの結合
同じように配列だけでなく、オブジェクトも結合させることができます。
1
2
3
4
5
const user1 = { name: "田中", age: 30 };
const user2 = { job: "エンジニア", city: "東京" };
const combinedUser = { ...user1, ...user2 };
console.log(combinedUser); // { name: '田中', age: 30, job: 'エンジニア', city: '東京' }
関数の引数として使用
スプレッド構文は関数の引数としても使用できます。
1
2
3
4
5
6
7
function sum(x, y, z) {
return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers)); // 出力: 6
文字列の分割
split
メソッドのは特定の区切り文字で文字列を分割したい時に使うメソッドですが、スプレッド構文を使うと文字列を個々の文字に分割することができます。
1
2
3
4
const word = "こんにちは";
const letters = [...word];
console.log(letters); // 出力: ["こ","ん","に","ち","は"]
スプレッド構文の応用的な使い方
この章では、スプレッド構文の応用的な使い方について解説します。
配列の一部を取り出して新しい配列を作成
配列の一部を取り出し、新しい配列を作成することができます。
1
2
3
4
5
const array = [1, 2, 3, 4, 5];
const [first, ...rest] = array;
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]
これは分割代入と呼ばれるJavaScriptの機能です。
first
にはarray
の最初の要素が割り当てられ、...rest
というスプレッド構文を使うことで、残りの要素を新しい配列として作成しています。
オブジェクトの特定のプロパティを除去
オブジェクトの特定のプロパティを取り出し、残りを新しいオブジェクトにまとめることができます。
1
2
3
4
5
const originalObject = { a: 1, b: 2, c: 3 };
const { b, ...rest } = originalObject;
console.log(b) // 2
console.log(rest); // { a: 1, c: 3 }
これも同じく分割代入と呼ばれるJavaScriptの機能です。
b
には、originalObject
のb
プロパティの値が割り当てられます。
...rest
は残りのすべてのプロパティを新しいオブジェクトとして作成しています。
配列の一部を別の配列に展開
配列の一部を取り出し、別の配列に展開することができます。
1
2
3
4
const array1 = [1, 2, 3];
const array2 = [4, 5, ...array1];
console.log(array2); // [4, 5, 1, 2, 3]
配列から重複を削除
Set
オブジェクトとスプレッド構文を使うことで配列から重複を削除することができます。Set
は重複する値を持たないため、配列をSet
に変換してからスプレッド構文を使って再び配列に戻すことで、重複を除いた配列を得ることができます。
1
2
3
4
5
6
const numbers = [1, 2, 3, 1, 2, 4];
// Setオブジェクトに変換して重複を削除
const uniqueArray = [...new Set(numbers)];
console.log(uniqueArray); // 出力: [1, 2, 3, 4]
使用する際の注意点
この章ではスプレッド構文を使う際の注意点を紹介します。
重複する部分は上書きされる
オブジェクトのプロパティが重複する場合、後にスプレッドされたものが前のものを上書きします。
上書きが発生する可能性がある場合は、プロパティの順序や重複に注意しましょう。
1
2
3
4
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }
無効なデータ型への展開はエラーになる
スプレッド構文はオブジェクト型(配列やオブジェクトなど)にのみ使用できます。プリミティブ型の値(文字列や数値など)に対して使用すると、エラーが発生します。
1
2
const notIterable = 123;
const copy = [...notIterable]; // エラーが発生
このコードを実行すると以下のようなエラーが出ます。
プリミティブ型ってなあに?
プリミティブ型とはプログラミングで使われる基本的なデータの種類のことを言うんだ。例えば文字列、数値、真偽値、未定義(Undefined)などの情報を扱う際に基本となるものだよ。
それに対し、配列やオブジェクトなどの情報はオブジェクト型(参照型)と呼ぶんだ。
展開する要素の変更に注意
スプレッド構文で作成された配列やオブジェクトでは元のデータの浅いコピー(シャローコピー)が作成されます。その際、要素がプリミティブ型かオブジェクト型かでコピーされる範囲が異なります。
配列
配列の一層目はコピーされる
要素がプリミティブ型の場合、その値は第一層にあるため、スプレッド構文によって新しい配列が作成されるとき、値自体がコピーされます。したがって、コピー元とコピー先の値を変更しても、それぞれに影響を与えることはありません。
1
2
3
4
5
6
7
8
9
10
let originalArray = [1, 2, 3];
let shallowCopy = [...originalArray]; // スプレッド構文でシャローコピーを作成
// shallowCopyを変更
shallowCopy[0] = 999;
// originalArrayとshallowCopyは異なる配列を参照しているため、
// 片方を変更してももう片方には影響しない。
console.log(originalArray); // 出力: [1, 2, 3]
console.log(shallowCopy); // 出力: [999, 2, 3]
配列の二層目はコピーされない
しかし、これは要素やプロパティがプリミティブ型に限られる場合のみ適用されます。要素やプロパティがオブジェクト型(配列やオブジェクト)の場合、それぞれのプロパティや要素は第二層以降のデータとなるため、その値はコピーされず、参照(データが保存されている場所のアドレス)がコピーされます。このため、データを変更すると、コピー元とコピー先の両方に影響を及ぼします。
1
2
3
4
5
6
7
8
9
10
const originalArray = [[1, 2], [3, 4]];
const shallowCopy = [...originalArray];
// データを変更
originalArray[0][1] = 99;
shallowCopy[1][0] = 5;
// 参照をコピーしているためお互いに影響を与える
console.log(originalArray); // [[1, 99], [5, 4]];
console.log(shallowCopy); // [[1, 99], [5, 4]];
具体的に説明すると、配列やオブジェクトはメモリ上の特定の場所に保存されています。これらの保存場所を示すアドレス(参照)を通じて、それらの値にアクセスします。アドレスは、保存場所を見つけるための情報であり、そのアドレスを使ってデータにアクセスし、変更を加えます。
つまり、元の配列やオブジェクトと、スプレッド構文を使って新しく作成された配列やオブジェクトでは、同じアドレスを使ってデータを取得・変更することになります。このため、どちらかのデータを変更すると、もう一方にも影響を与えることになります。
オブジェクト
オブジェクトの一層目はコピーされる
スプレッド構文で作成されたオブジェクトも、配列と同様にシャローコピーされます。プロパティの値がプリミティブ型の場合、第一層のデータは参照先ではなく値自体がコピーされるため、変更が相互に影響を与えることはありません。
1
2
3
4
5
6
7
8
9
const originalObject = { a: 1, b: { c: 2 } };
const shallowCopyObject = { ...originalObject };
// コピーのオブジェクトの一層目のデータを変更
shallowCopyObject.a = 99;
// 1層目のデータはコピーされているため影響を受けない
console.log(originalObject); // { a: 1, b: { c: 2 } }
console.log(shallowCopyObject); // { a: 99, b: { c: 2 } }
オブジェクトの二層目以降はコピーされない
同様にプロパティの値がオブジェクト型の場合、ネストされたデータ(第二層以降)は参照がコピーされるため、変更が双方に影響を与えます。
1
2
3
4
5
6
7
8
9
const originalObject = { a: 1, b: { c: 2 } };
const shallowCopyObject = { ...originalObject };
// コピーのネストされたオブジェクトを変更
shallowCopyObject.b.c = 99;
// 参照をコピーしているため元のデータにも影響
console.log(originalObject); // { a: 1, b: { c: 99 } }
console.log(shallowCopyObject); // { a: 1, b: { c: 99 } }
この記事のまとめ
- スプレッド構文は、3つの
.
を使って、配列やオブジェクトの要素を展開することができる。 - スプレッド構文を使って新しい配列やコピーを作成することができる。
- スプレッド構文では配列やオブジェクトはシャドーコピーで作成される
