WebEngine

だらだらと綴る技術系メモ

スプレッド構文の使い方【JavaScript】

スプレッド構文(演算子)の使い方

スプレッド構文

スプレーや霧吹きは、高圧の空気などを用いて、液体を霧状に噴出する装置です。
この機構を最初に思いついた人は天才だなあ、と思います。
そういうものはたくさんありますが、自分の身近にあるものは尚更そう感じます。

そんなスプレーのように、配列やオブジェクトの値を拡散させることが可能なのが、スプレッド構文です。

スプレッド演算子、という呼び名も使われているようですが、MDNでは スプレッド構文となっているので、ここではその呼称で統一します。


1. 基本的な使い方
2. Arrayリテラルでの使用例
3. Objectリテラルでの使用例
4. 注意点
5. 参考


1. 基本的な使い方

以下の例では、関数sumの引数に、構文である...をつけて配列numsを渡しています。このように記述することで、配列の値を、sum関数のx、y、zに割り当てることができます。

const sum = (x, y, z) => x + y + z
const nums = [1, 5, 15]
console.log( sum(...nums) )  // 21


また、関数の引数をスプレッド構文にすれば、関数に渡される引数を配列として扱うことができます。

const test = (...nums)  => nums[1]
console.log(test(1, 5, 15))  // 5


2. Arrayリテラルでの使用例

配列のコピー

スプレッド構文によるコピーはシャローコピーとなります。

const ary1 = [1, 2, 3]
// 配列のコピー
const ary2 = ary1  // 参照渡し
const ary3 = [...ary1]  // シャローコピー
// コピー検証
console.log(ary1 === ary2)  // true
console.log(ary1 === ary3)  // false

// 要素を追加した新しい配列を作成
const ary4 = ['hello', ...ary1, 7] // ['hello', 1, 2, 3, 7]


シャローコピーなので、ネストになっている配列とオブジェクトには注意が必要です。
(対象がネストになっていると、ディープコピーではすべての階層について実体をコピーするのに対し、シャローコピーでは最初の1階層のみ実体がコピーされる)

const baseArray = [1, [2, 3], [4, 5]]
let copyArray = [...baseArray]
copyArray[0] = 'aaa'
copyArray[1][0] = 'bbb'
console.log(baseArray, copyArray)  // [ 1, [ 'bbb', 3 ], [ 4, 5 ] ] [ 'aaa', [ 'bbb', 3 ], [ 4, 5 ] ]


配列のマージ

concat()を使わず、簡潔に書けるようになりました。

const ary1 = ["a", 0, "b"]
const ary2 = [1, "hello", 99]
const ary3 = [...ary1, ...ary2]  // ["a", 0, "b", 1, "hello", 99]


3. Objectリテラルでの使用例

コピーとマージの方法、結果は配列と同じです。

オブジェクトのコピー

const obj1 = {name: "tanaka", age: 20}
// オブジェクトのコピー
const obj2 = obj1  // 参照渡し
const obj3 = {...obj1}  // シャローコピー
// コピー検証
console.log(obj1 === obj2)  // true
console.log(obj1 === obj3)  // false

// 要素を追加した新しいオブジェクトを作成
const obj4 = {...obj1, hobby: "guiter"}  // { name: "tanaka", age: 20, hobby: "guiter" }

配列と同じく、ネストされているオブジェクトには注意。

const baseObject = {
  name: {
    firstname: "Taro",
    familyname: "Tanaka"
  },
  age: 20
}
let copyObject = {...baseObject}
copyObject.name.firstname = "Jiro"
copyObject.age = 35
console.log(baseObject, copyObject)
// {age: 20, name: { familyname: "Tanaka", firstname: "Jiro" } }
// {age: 35, name: { familyname: "Tanaka", firstname: "Jiro" } }


オブジェクトのマージ

const human = {name: "tanaka", age: 20}
const subinfo = {hobby: "guiter", job: "enginner"}
const tanaka = {...human, ...subinfo}  // {name: "tanaka", age: 20, hobby: "guiter", job: "enginner"}


4. 注意点

オブジェクト内に配列は展開できるが、配列にオブジェクトは展開できない

以下のようにオブジェクトを配列内に展開しようとするとエラーになります。

const obj = {name: "tanaka", age: 20}
const ary = [1, ...obj, 2]  // TypeError: obj is not iterable

ただし、配列をオブジェクトに展開することは可能です。

const ary = ["Takana play guiter.", "Human data"]
const obj = {name: "tanaka",  age: 20, ...ary}  // {0: "Takana play guiter.", 1: "Human data", name: "tanaka", age: 20}


null, undefined

nullやundefinedをスプレッド構文で扱おうとすると、配列はエラーになるが、オブジェクトの場合はエラーになりません。

// 配列
[...null]  // Uncaught TypeError: object null is not iterable
[...undefined]  // Uncaught TypeError: undefined is not iterable
// オブジェクト
{...null}  // {}
{...undefined}  // {}


IE未対応

言わずもがな。


5. 参考