1. ホーム
  2. JavaScript

【JavaScript】分割代入(Destructuring)の使い方|配列・オブジェクトから値を取り出す

Share

配列やオブジェクトから値を取り出して変数に入れるとき、1つずつインデックスやプロパティを指定して書くと、どうしても記述が長くなりがちです。そんなときに役立つのが分割代入(Destructuring)です。この記事では、配列・オブジェクトから値を取り出す基本から、別名やデフォルト値の付け方、ネストした分割代入、関数引数での使い方、残余(rest)との組み合わせ、2つの変数の入れ替えまで、初心者にもわかるように順番に解説します。

分割代入(Destructuring)とは

分割代入は、配列やオブジェクトの中身を取り出して、それぞれ別々の変数に代入するための書き方です。これまで const name = user.name; のように1行ずつ書いていたものを、まとめて1行で書けるようになります。「中身を分けて(分割して)代入する」というイメージのとおり、ひとかたまりのデータを個々の変数にばらして受け取れるのが特徴です。

なお、ピリオド3つで書くスプレッド構文(...)が「値を展開して並べる(出す側)」だったのに対し、分割代入は「並んだ値を変数で受け取る(取り出す側)」の書き方だと考えると整理しやすいでしょう。

配列の分割代入

配列の場合は、代入する左辺を角かっこ [ ] で書きます。配列の先頭から順番に、それぞれの変数へ値が入っていきます。取り出す位置は順番で決まるため、変数名は自由に付けられます。

app.js
const colors = ["red", "green", "blue"];

// 先頭から順番に変数へ代入される
const [first, second, third] = colors;

console.log(first);  // "red"
console.log(second); // "green"
console.log(third);  // "blue"

不要な要素はカンマだけを置いて読み飛ばせます。たとえば2番目だけが欲しいときは、次のように書きます。

app.js
const colors = ["red", "green", "blue"];

// 1番目を飛ばして、2番目だけを取り出す
const [, second] = colors;

console.log(second); // "green"

オブジェクトの分割代入

オブジェクトの場合は、左辺を波かっこ { } で書きます。配列と違い、順番ではなくプロパティ名で取り出す点が大きな違いです。そのため、変数名は取り出したいプロパティ名と同じにする必要があります。

app.js
const user = { name: "Taro", age: 20 };

// プロパティ名と同じ名前の変数に取り出す
const { name, age } = user;

console.log(name); // "Taro"
console.log(age);  // 20

プロパティ名で取り出すため、書く順番は自由です。const { age, name } = user; のように入れ替えても、それぞれ正しいプロパティの値が入ります。

別名(エイリアス)を付けて取り出す

プロパティ名とは違う変数名で受け取りたいときは、プロパティ名: 新しい変数名 の形で別名を付けられます。すでに同じ名前の変数がある場合や、より分かりやすい名前にしたい場合に便利です。

app.js
const user = { name: "Taro", age: 20 };

// name を userName、age を userAge という変数名で受け取る
const { name: userName, age: userAge } = user;

console.log(userName); // "Taro"
console.log(userAge);  // 20

ここで注意したいのは、別名を付けると元のプロパティ名の変数(この例では nameage)は作られないという点です。値は新しい名前の変数にだけ入ります。

デフォルト値を指定する

取り出したいプロパティが存在しないとき、変数には undefined が入ります。これを避けたいときは、=デフォルト値を指定できます。プロパティが見つからなかった場合だけ、その値が使われます。

app.js
const user = { name: "Taro" };

// role は存在しないので、デフォルト値の "guest" が使われる
const { name, role = "guest" } = user;

console.log(name); // "Taro"
console.log(role); // "guest"

別名とデフォルト値は同時に使えます。その場合は プロパティ名: 新しい変数名 = デフォルト値 の順で書きます(例: const { role: userRole = "guest" } = user;)。

デフォルト値が使われるのは undefined のときだけ

デフォルト値でつまずきやすいのが、適用される条件です。デフォルト値が使われるのは、取り出した値が undefined のとき(=プロパティが存在しない、または値が明示的に undefined のとき)だけです。値が null0、空文字 "" の場合は「値が存在する」とみなされ、デフォルト値は使われません

app.js
// 値が null のケース
const data = { count: null };

// null は undefined ではないため、デフォルト値は使われない
const { count = 0 } = data;

console.log(count); // null(0 にはならない)

null のときも初期値に置き換えたい場合は、分割代入のデフォルト値ではなく、取り出したあとに ??(Null 合体演算子)などで別途処理する必要があります。「デフォルト値は undefined 専用」と覚えておくと、思わぬ値が残るトラブルを避けられます。

ネストした分割代入

オブジェクトの中にオブジェクトが入れ子(ネスト)になっている場合も、構造に合わせて波かっこを重ねることで、奥にある値を直接取り出せます。

app.js
const user = {
  name: "Taro",
  address: {
    city: "Tokyo",
    zip: "100-0001",
  },
};

// address の中の city を直接取り出す
const { name, address: { city } } = user;

console.log(name); // "Taro"
console.log(city); // "Tokyo"

ここで間違えやすいのが、address: { city } と書いたとき、address という変数は作られないという点です。この address: は「address の中をさらに分解する」という指示であり、city だけが変数として作られます。address 自体も使いたい場合は、別途 const { address } = user; のように取り出してください。

関数の引数で分割代入する

分割代入は、関数の引数を受け取る部分でも使えます。オブジェクトを引数として渡し、その場で必要なプロパティだけを取り出せるため、options.widthoptions.height のように毎回 options. を書く手間が省けます。

app.js
// 引数のオブジェクトから width と height を取り出す
function createBox({ width, height }) {
  return width * height;
}

const size = { width: 100, height: 50 };
console.log(createBox(size)); // 5000

引数の分割代入でもデフォルト値を組み合わせられます。指定されなかったプロパティに初期値を与えられるので、設定オブジェクトを受け取る関数で重宝します。

app.js
// color が渡されなければ "black" を使う
function draw({ width, height, color = "black" }) {
  console.log(`${width}x${height} / ${color}`);
}

draw({ width: 100, height: 50 });                 // 100x50 / black
draw({ width: 100, height: 50, color: "red" });   // 100x50 / red

残余(rest)と組み合わせて残りをまとめる

取り出したい値の後ろに ... を付けると、残りの要素やプロパティをまとめて1つにできます。これを残余(rest)と呼びます。配列なら残りが配列に、オブジェクトなら残りがオブジェクトにまとまります。

app.js
const numbers = [1, 2, 3, 4, 5];

// 先頭を取り出し、残りは rest という配列にまとめる
const [head, ...rest] = numbers;

console.log(head); // 1
console.log(rest); // [2, 3, 4, 5]

const user = { id: 1, name: "Taro", age: 20 };

// id を取り出し、残りのプロパティは others にまとめる
const { id, ...others } = user;

console.log(id);     // 1
console.log(others); // { name: "Taro", age: 20 }

残余は必ず末尾に1つだけ書きます。[...rest, last] のように途中に書くと構文エラーになる点に注意してください。

2つの変数の値を入れ替える

配列の分割代入を使うと、一時変数を用意せずに2つの変数の値を入れ替える(スワップする)ことができます。右辺で配列を作り、それを左辺の2つの変数に割り当て直すという仕組みです。

app.js
let a = 1;
let b = 2;

// 一時変数なしで値を入れ替える
[a, b] = [b, a];

console.log(a); // 2
console.log(b); // 1

文の先頭で { } を使うとエラーになる

すでに宣言した変数に、オブジェクトの分割代入で値を入れ直したいことがあります。このとき constlet を付けずに文の先頭で { から書き始めると、エラーになります。JavaScript が行頭の { を「分割代入」ではなく「コードブロックの始まり」と解釈してしまうためです。

app.js
let name, age;
const user = { name: "Taro", age: 20 };

// 行頭の { がブロックと解釈され、構文エラーになる
// { name, age } = user;  // SyntaxError

// 全体を ( ) で囲むと、分割代入として正しく動く
({ name, age } = user);

console.log(name); // "Taro"
console.log(age);  // 20

このように、宣言キーワードなしでオブジェクトの分割代入をするときは、文全体を丸かっこ ( ) で囲みます。const { name } = user; のように宣言とセットで書く場合は行頭が const になるため、この問題は起きません。

まとめ

分割代入を使うと、配列やオブジェクトから必要な値を、短く読みやすいコードで取り出せます。

  • 配列は [ ] で順番に、オブジェクトは { } でプロパティ名で取り出す
  • オブジェクトは プロパティ名: 別名 で別の変数名にでき、= 値 でデフォルト値を指定できる
  • デフォルト値が使われるのは値が undefined のときだけで、null には適用されない
  • ネストや関数の引数でも使え、...(残余)で残りをまとめられる
  • 宣言なしのオブジェクト分割代入は、文全体を ( ) で囲む

まずはオブジェクトからのプロパティ取り出しや、関数引数での分割代入から試して、すっきりとした書き方に慣れていきましょう。

参考リンク