配列の分割代入で先頭と残りを取り出す
このレッスンで分かること
const [a, b, c] = arrで配列を変数にまとめて展開できますconst [head, ...tail] = arrで「先頭と残り」を 1 行で分けられます- 最小例は
const [first, ...rest] = [10, 20, 30]→first = 10,rest = [20, 30]
配列の分割代入で先頭と残りを取り出す とは
配列の分割代入と rest 記法で、先頭の要素と残りの要素を一度に取り出す書き方を学ぶ。本レッスンでは、配列の分割代入で先頭と残りを取り出す の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
配列の分割代入で先頭と残りを取り出す
配列の中身を 1 つずつ取り出すのに、毎回 array[0]、array[1] と書くのは読みづらく、ミスも起きやすいです。JavaScript の 分割代入 (destructuring assignment) を使うと、配列の中身をまとめて変数に展開できます。さらに ...rest 記法を組み合わせれば、「先頭の 1 個と残り全部」のような分け方もスマートに書けます。この章では分割代入の基本構文と、rest を活用した実用パターンを身につけます。
分割代入は 「形に名前をつける」 感覚で書ける。
const [head, ...tail] = listは「先頭をhead、残りをtailに」と読み下せる。
分割代入とは何か
分割代入は、ES2015 (ES6) で追加された構文で、配列やオブジェクトをパターンマッチング風に分解できます。配列の場合、左辺に角括弧 [] を書き、その中に変数名を並べると、右辺の配列の各要素が対応する位置の変数に代入されます。
JavaScript
const scores = [80, 90, 70];
const [a, b, c] = scores;
console.log(a, b, c); // 80 90 70従来の書き方と比べると、その差は一目瞭然です。
JavaScript
// Before: インデックス指定でひとつずつ
const scores = [80, 90, 70];
const a = scores[0];
const b = scores[1];
const c = scores[2];
// After: 分割代入でまとめて
const [a, b, c] = scores;| パターン | 結果 |
|---|---|
const [a, b] = [1, 2] | a=1, b=2 |
const [a, , c] = [1, 2, 3] | a=1, c=3 (中央スキップ) |
const [a = 0] = [] | a=0 (デフォルト値) |
const [head, ...rest] = [1, 2, 3] | head=1, rest=[2, 3] |
「先頭から順に何個取るか」が左辺の形でひと目で分かる。これが可読性の向上に直結する。
rest 記法で残りをまとめる
配列分割代入の真価は、...rest 記法と組み合わせたときに発揮されます。const [head, ...tail] = arr と書けば、head には 1 番目の要素、tail には残り全部を配列として受け取れます。tail は元配列が空でも空配列 [] になり、undefined にはなりません。
JavaScript
const nums = [10, 20, 30, 40];
const [first, ...rest] = nums;
console.log(first); // 10
console.log(rest); // [20, 30, 40]
restは必ず最後に書く。途中に...midと書いてしまうと構文エラーになる。
動きを追ってみる
図の流れを順序リストで書き直すと、次の通りです。
- 元の配列
[10, 20, 30, 40]を右辺に置く - 左辺
[head, ...rest]のパターンと位置を合わせる headに先頭要素10が代入されるrestに残り[20, 30, 40]が 新しい配列として 代入される- 元の配列は変更されない
図のとおり、head には先頭 1 個だけが値として入り、rest には残りが配列として入ります。rest は新しい配列なので、元の nums を破壊しません。nums 自体はそのままです。
よくある間違い
第 1 に、rest の後ろに変数を続けて書くと SyntaxError になります。const [...rest, last] = arr は許されません。第 2 に、空配列に対して const [first] = [] とした場合、first は undefined になります。これを避けるにはデフォルト値を書きます。
JavaScript
const [first = 0, ...rest] = [];
console.log(first); // 0
console.log(rest); // []第 3 に、文字列も分割代入できますが、これは「配列っぽい」iterable として扱われるためです。const [a, b] = "hi" で a が "h"、b が "i" になります。混乱の元なので、配列以外には使わない方が無難です。
分割代入は
iterableプロトコルに従う値なら何でも分解できる。Array、Map、Set、文字列が代表例。
スワップやネストにも使える
分割代入は 値の入れ替え (swap) にも応用できます。一時変数を使わずに、たった 1 行で a と b を交換できます。これは現場でもよく使うイディオムです。
JavaScript
let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a, b); // 2 1ネストした配列も、左辺に同じ形を書けば取り出せます。例えば [[1, 2], [3, 4]] から 1 だけ取り出すなら const [[head]] = matrix です。可読性は落ちるので、深くネストしている場合は途中で変数に取り出す方がおすすめです。
ここまでの要点
const [a, b] = arr でまとめて取り出し、const [head, ...tail] = arr で先頭と残りに分ける。rest は必ず最後。デフォルト値で空配列にも対応できる。
やってみよう
配列 arr を受け取り、{ first, rest } という形のオブジェクトを返す headAndTail 関数を書いてみましょう。first には先頭要素、rest には残りの要素 (配列) を入れます。配列が空のときは first を null、rest を [] にします。if 文で長さチェックを入れつつ、const [a, ...b] = arr の形で取り出すのがポイントです。完成したら length が 0、1、3 の配列で挙動を確かめてみましょう。map や filter と組み合わせると、リスト処理の幅がぐっと広がります。再帰関数で「先頭を処理 + 残りを再帰」というパターンも書きやすくなり、関数型プログラミングの世界にも一歩近づけます。
よくある質問
Q. 存在しないキーを分割代入するとどうなりますか?
A. 値は undefined になります。デフォルト値を指定したい場合は const { name = 'guest' } = user; のように = で書けます。深いネストでも const { profile: { age = 0 } = {} } = user; のように途中の null/undefined を防げます。
Q. 別名で受け取ることはできますか?
A. const { name: userName } = user; のように : で別名を付けられます。コンポーネント間でプロパティ名が衝突しないようにしたいときや、短い変数名にリネームしたいときに使うと可読性が上がります。
Q. 配列の分割代入で先頭と残りを分けるには?
A. const [first, ...rest] = list; と書けば先頭が first、残りが配列 rest に入ります。スキップしたい要素はカンマで空けて const [, second] = list; とできます。タプル型と相性が良く、関数の複数戻り値を分解するときにも便利です。
次のレッスン
次は オブジェクトの分割代入で必要なキーだけ取り出す で、配列の分割代入と rest 記法で、先頭の要素と残りの要素を一度に取り出す書き方を学ぶ を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 配列分割代入 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 配列分割代入 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- 配列の分割代入
const [first, ...rest] = arrを使うこと - 空配列のときは
firstをnull、restを[]にすること - 返り値は
{ first, rest }というキーを持つオブジェクトにすること
入出力例
test-cases.txt
headAndTail([10,20,30]) → {"first":10,"rest":[20,30]}
headAndTail([42]) → {"first":42,"rest":[]}
headAndTail([]) → {"first":null,"rest":[]}
headAndTail([1,2,3,4,5]) → {"first":1,"rest":[2,3,4,5]}