✏️

分割代入を使って配列を先頭とそれ以外で分割する

okkun05242022/12/02に公開

ワスド株式会社の okkun と申します。
以前ワスドで Zenn Publication を始めた記事を投稿しましたがそれ以降なかなか投稿するタイミングが生まれず、ようやく今日から本腰を入れられそうということになり記事を書いていこうと思います。

https://zenn.dev/wasd_inc/articles/2408c4d70bb39a

背景

配列を先頭要素と2個目以降で別々で定義し直す実装が必要になったので、どういう方法があるかを調べていました。

// 元となる配列
const arrayNum = [1, 2, 3, 4, 5];

// 先頭要素だけ取得したイメージ
const firstNum = 1; 
// 2個目以降を取得したイメージ
const otherNums = [2, 3, 4, 5];

Array.shift()を使う場合

配列から先頭要素を切り出す関数として、Array.shift()があり、最初はこれを使おうとしました。

const firstNum = arrayNum[0];
const otherNums = arrayNum.shift();

ここで、shift()の返却値が想定したものと合っているか気になったのでドキュメントを確認しました。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/shift

どうやらこの関数は切り出した先頭要素を返却値とし、元の配列の先頭要素を削除するようです。
想定と違った上に破壊的変更が伴っている・・・

ということで、Array.shift()で実現する場合はotherNumsを元の配列からコピーした上でshift()を行う必要がありそうです。

const firstNum = arrayNum[0];
// arrayNumのコピーを作成(Shallow Copy)
const otherNums = arrayNum.concat();
otherNums.shift();

console.log(firstNum); // 1
console.log(otherNums); // [2, 3, 4, 5]

ちなみに、arrayNumが数字ではなくオブジェクトの配列である場合、Shallow CopyではなくDeep Copyで配列を複製する必要があります。

Array.slice()を使う場合

Array.shift()だと配列のコピー処理が追加で入ってしまうので、これを嫌うのであればArray.slice()による範囲指定の切り出しになる?と思いドキュメントを見ました。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

破壊的変更は伴わないようなので、shift()よりは直感的です。

const firstNum = arrayNum[0];
const otherNums = arrayNum.slice(1);

console.log(firstNum); // 1
console.log(otherNums); // [2, 3, 4, 5]

分割代入を使う場合

ここまでArrayの関数を使って対応しましたが、配列の分割代入を使うことで1行のコードで収まることに気づきました。
下記のように書くことで先頭要素をfirstNum, それ以降を配列としてotherNumsに代入されます。
この方がシンプルでよさそうです。

const [firstNum, ...otherNums] = arrayNum;

console.log(firstNum); // 1
console.log(otherNums); // [2, 3, 4, 5]

おまけ

取得元の配列の要素数が0個、1個であるとき、上記で挙げたそれぞれの処理がどうなるのかも見てみました。
結果はどれも同じになります。

const arrayNum = [1];

/* Array.shift() */
const firstNum = arrayNum[0];
const otherNums = arrayNum.concat();
otherNums.shift();

console.log(firstNum); // 1
console.log(otherNums); // []

/* Array.slice() */
const firstNum = arrayNum[0];
const otherNums = arrayNum.slice(1);

console.log(firstNum); // 1
console.log(otherNums); // []

/* 配列の分割代入 */
const [firstNum, ...otherNums] = arrayNum;

console.log(firstNum); // 1
console.log(otherNums); // []
const arrayNum = [];

/* Array.shift() */
const firstNum = arrayNum[0];
const otherNums = arrayNum.concat();
otherNums.shift();

console.log(firstNum); // undefined
console.log(otherNums); // []

/* Array.slice() */
const firstNum = arrayNum[0];
const otherNums = arrayNum.slice(1);

console.log(firstNum); // undefined
console.log(otherNums); // []

/* 配列の分割代入 */
const [firstNum, ...otherNums] = arrayNum;

console.log(firstNum); // undefined
console.log(otherNums); // []

Discussion

ログインするとコメントできます