分割代入

分割代入(Destructuring assignment)構文は、配列かオブジェクトからデータを取り出して別個の変数に代入することを可能にする JavaScript の式です。

構文

var a, b, rest;
[a, b] = [1, 2]
console.log(a) // 1
console.log(b) // 2

[a, b, ...rest] = [1, 2, 3, 4, 5]
console.log(a) // 1
console.log(b) // 2
console.log(rest) // [3, 4, 5]

({a, b} = {a:1, b:2})
console.log(a) // 1
console.log(b) // 2

({a, b, ...rest} = {a:1, b:2, c:3, d:4}) //ES7 - Firefox 47a01 では未実装

説明

オブジェクトリテラルと配列リテラルによって、いくつかのデータをアドホックにまとめられます。

var x = [1, 2, 3, 4, 5]

分割代入の構文はオブジェクトや配列のリテラルと似ています。右辺の各要素が代入される変数を、左辺に記述します。

var x = [1, 2, 3, 4, 5]
var [y, z] = x
console.log(y); // 1
console.log(z); // 2

この機能は、Perl や Python などの言語に存在する機能に似ています。

配列の分割代入

簡単な例

var foo = ["one", "two", "three"];

var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"

宣言後の割り当て

変数の宣言とは別に分割代入で値を代入できます。

var a, b;

[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

既定値の設定

配列から取り出した値が undefined だった場合に使用される既定値を指定できます。

var a, b;

[a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7

変数の入れ替え

分割代入を使用して、複数の変数の値を入れ替えることができます。

分割代入なしで、2つの値をスワップするにはテンポラリ変数が必要です。(または、 一部の低レベルの言語では、XOR-swap trick (日本語版) があります)。

var a = 1;
var b = 3;

[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1

関数から返された配列の解析

関数は配列を返すことができます。分割代入によって、返された配列の使用をより簡潔に記述できます。

この例では、f() は出力として値 [1, 2] を返しており、分割代入により 1 行で解析できます。

function f() {
  return [1, 2];
}

var a, b; 
[a, b] = f(); 
console.log(a); // 1
console.log(b); // 2

返り値の無視

興味を持っていない戻り値を無視することができます:

function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

このようにすべての返り値を無視することもできます:

[,,] = f();

正規表現のマッチからの値取得

正規表現オブジェクトの exec() メソッドはマッチを見つけ、最初にマッチした文字列全体の一部と、正規表現内の各括弧で囲まれたグループにマッチした文字列の部分を含む配列を返します。分割代入によって、簡単にこの配列の一部分を取り出せます。また必要でない場合は、完全一致を無視できます。

var url = "https://developer.mozilla.org/en-US/Web/JavaScript";

var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]

var [, protocol, fullhost, fullpath] = parsedURL;

console.log(protocol); // "https"

オブジェクトの分割代入

簡単な例

var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true 

宣言のない割り当て

分割代入は代入文で宣言することなく行うことができます。

var a, b;

({a, b} = {a:1, b:2});

代入文の周りの ( .. ) は宣言のないオブジェクトリテラル分割代入を使用するときに必要な構文です。

{a, b} = {a:1, b:2} は有効なスタンドアロンの構文ではありません。というのも、左辺の {a, b} はブロックでありオブジェクトリテラルではないと考えられるからです。

しかしながら、({a, b} = {a:1, b:2}) 形式は有効です。var {a, b} = {a:1, b:2} と考えられるためです。

異なる名前を持つ変数への代入

オブジェクトから変数を取り出して、オブジェクトのプロパティとは異なる名前の変数に代入することができます。

var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
 
console.log(foo); // 42 
console.log(bar); // true  

既定値の設定

オブジェクトから取り出した値が undefined であるときの既定値を、変数に割り当てることができます。

var {a=10, b=5} = {a: 3};

console.log(a); // 3
console.log(b); // 5

関数の引数に対する規定値の設定

ES5バージョン

function drawES5Chart(options) {
  options = options === undefined ? {} : options;
  var size = options.size === undefined ? 'big' : options.size;
  var cords = options.cords === undefined ? { x: 0, y: 0 } : options.cords;
  var radius = options.radius === undefined ? 25 : options.radius;
  console.log(size, cords, radius);
  // now finally do some chart drawing
}

drawES5Chart({
  cords: { x: 18, y: 30 },
  radius: 30
});

ES2015バージョン

function drawES2015Chart({size = 'big', cords = { x: 0, y: 0 }, radius = 25} = {}) {
  console.log(size, cords, radius);
  // do some chart drawing
}

// Firefoxでは、分割代入に対するデフォルト値はまだ実装されていません (後述)。 
// 回避策は、引数を以下のように記述することです:
// ({size: size = 'big', cords: cords = { x: 0, y: 0 }, radius: radius = 25} = {})

drawES2015Chart({
  cords: { x: 18, y: 30 },
  radius: 30
});

入れ子になったオブジェクトと配列の分割代入

var metadata = {
    title: "Scratchpad",
    translations: [
       {
        locale: "de",
        localization_tags: [ ],
        last_edit: "2014-04-14T08:43:37",
        url: "/de/docs/Tools/Scratchpad",
        title: "JavaScript-Umgebung"
       }
    ],
    url: "/en-US/docs/Tools/Scratchpad"
};

var { title: englishTitle, translations: [{ title: localeTitle }] } = metadata;

console.log(englishTitle); // "Scratchpad"
console.log(localeTitle);  // "JavaScript-Umgebung"

イテレーターでの分割代入の利用

var people = [
  {
    name: "Mike Smith",
    family: {
      mother: "Jane Smith",
      father: "Harry Smith",
      sister: "Samantha Smith"
    },
    age: 35
  },
  {
    name: "Tom Jones",
    family: {
      mother: "Norah Jones",
      father: "Richard Jones",
      brother: "Howard Jones"
    },
    age: 25
  }
];

for (var {name: n, family: { father: f } } of people) {
  console.log("Name: " + n + ", Father: " + f);
}

// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"

引数に指定されたオブジェクトの属性への参照

function userId({id}) {
  return id;
}

function whois({displayName: displayName, fullName: {firstName: name}}){
  console.log(displayName + " is " + name);
}

var user = { 
  id: 42, 
  displayName: "jdoe",
  fullName: { 
      firstName: "John",
      lastName: "Doe"
  }
};

console.log("userId: " + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"

上記ではiddisplayNamefirstNameをオブジェクトから取得し、出力します。

計算されたオブジェクトのプロパティの名前と分割代入

object literalsのような計算されたプロパティの名前も分割代入で使用できます。

let key = "z";
let { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"

仕様

仕様 ステータス コメント
ECMAScript 2015 (6th Edition, ECMA-262)
Destructuring assignment の定義
標準 初期定義。
ECMAScript 2017 Draft (ECMA-262)
Destructuring assignment の定義
ドラフト  

ブラウザ実装状況

機能 Chrome Firefox (Gecko) Edge Internet Explorer Opera Safari
基本サポート 49.0 2.0 (1.8.1) 14[1] 未サポート 未サポート 7.1
計算されたプロパティの名前 49.0 34 (34) 14[1] 未サポート 未サポート 未サポート
スプレッドオペレータ 49.0 34 (34) 12[1] ? ? ?
機能 Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
基本サポート 未サポート 49.0 1.0 (1.0) 未サポート 未サポート 8 49.0
計算されたプロパティの名前 未サポート 49.0 34.0 (34) 未サポート 未サポート 未サポート 49.0
スプレッドオペレータ 未サポート 49.0 34.0 (34) ? ? ? 49.0

[1] `about:flags` で "試験的な JavaScript 機能を有効にする" の有効化が必要です。

Firefox固有のメモ

  • Firefoxは分割代入に対してJS1.7で非標準な言語拡張を提供しています。この拡張はGecko 40 (Firefox 40 / Thunderbird 40 / SeaMonkey 2.37)で削除されました。バグ 1083498をご覧ください。
  • Gecko 41 (Firefox 41 / Thunderbird 41 / SeaMonkey 2.38) より ES2015 仕様に準拠するため、([a, b]) = [1, 2]({a, b}) = { a: 1, b: 2 } のように括弧でくくる分割代入は無効になり SyntaxError が発生します。詳しくは Jeff Walden のブログ記事および バグ 1146136 をご覧ください。

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: chikoski, lv7777, yyss, shide55
 最終更新者: chikoski,