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

構文

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20


// Stage 3 proposal
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); //{c: 30, d: 40}

説明

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

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();

配列の残余部分を変数に代入する

配列を分割するときに残余パターンを使用して、配列の残りの部分を取り出して変数に代入できます:

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

左辺側で残余要素とともに末尾のカンマが使用されていると、SyntaxError が発生しますので注意してください:

var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma

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

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

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

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

console.log(parseProtocol('https://developer.mozilla.org/en-US/Web/JavaScript')); // "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

異なる名前の変数に代入して既定値を設定する

プロパティに対して、1) オブジェクトから取り出して異なる名前の変数に代入することと、2) 取り出した値が undefined である場合に既定値を代入することの両方が可能です。

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

console.log(aa); // 3
console.log(bb); // 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
}

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

drawES2015Chart の関数シグネチャでは分割した左辺が、右辺にあるからのオブジェクトリテラルに代入されます: {size = 'big', cords = {x: 0, y: 0}, radius = 25} = {}。右辺のの代入がない関数を記入することもできます。しかし右辺の代入を取り除くと、関数は実行されたときに少なくともひとつの引数が提供されることを期待します。一方、この形式では引数を与えずに drawES2015Chart() を呼び出せます。この設計は引数を指定せずに関数を呼び出せるようにしたい場合に役に立ちます。またもう一方の形式は、オブジェクトを確実に関数に渡したい場合に役に立ちます。

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

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, 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"

オブジェクトの分割代入の残余

Rest/Spread Properties for ECMAScript 提案 (ステージ 3) は、分割代入に rest 構文を追加します。残余プロパティは、分割パターンによってすでに取り出されていない、残りの列挙可能なプロパティのキーを収集します。

let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10 
b; // 20 
rest; // { c: 30, d: 40 }

無効な JavaScript 識別子をプロパティ名として使用する

JavaScript で有効な代替識別子を与えることにより、JavaScript で有効ではない 識別子 であるプロパティ名を分割代入で使用できます。

const foo = { 'fizz-buzz': true };
const { 'fizz-buzz': fizzBuzz } = foo;

console.log(fizzBuzz); // "true"

仕様

仕様書 策定状況 コメント
ECMAScript 2015 (6th Edition, ECMA-262)
Destructuring assignment の定義
標準 初期定義
ECMAScript Latest Draft (ECMA-262)
Destructuring assignment の定義
ドラフト  
Rest/Spread Properties for ECMAScript Draft ステージ 3 草案

ブラウザー実装状況

機能ChromeEdgeFirefoxInternet ExplorerOperaSafari
基本対応4914411 なし あり8
Computed property names491434 なし あり なし
Rest in arrays4914234 なし あり なし
Rest in objects60 なし55 なし あり なし
機能Android webviewChrome for AndroidEdge mobileFirefox for AndroidOpera AndroidiOS SafariSamsung Internet
基本対応494914411 あり85.0
Computed property names49491434 あり なし5.0
Rest in arrays494914234 あり なし5.0
Rest in objects6060 なし55 あり なし なし

1. Firefox provided a non-standard destructuring implementation from Firefox 2 to 40.

2. From version 14: this feature is behind the Enable experimental Javascript features preference.

関連情報

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

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