From 33058f2b292b3a581333bdfb21b8f671898c5060 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:40:17 -0500 Subject: initial commit --- .../operators/destructuring_assignment/index.html | 444 +++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 files/ja/web/javascript/reference/operators/destructuring_assignment/index.html (limited to 'files/ja/web/javascript/reference/operators/destructuring_assignment') diff --git a/files/ja/web/javascript/reference/operators/destructuring_assignment/index.html b/files/ja/web/javascript/reference/operators/destructuring_assignment/index.html new file mode 100644 index 0000000000..99361d3319 --- /dev/null +++ b/files/ja/web/javascript/reference/operators/destructuring_assignment/index.html @@ -0,0 +1,444 @@ +--- +title: 分割代入 +slug: Web/JavaScript/Reference/Operators/Destructuring_assignment +tags: + - Destructuring + - Destructuring_assignment + - ECMAScript 2015 + - ES6 + - JavaScript + - Language feature + - Nested object and array destructuring + - Operator + - 分割代入 + - 演算子 +translation_of: Web/JavaScript/Reference/Operators/Destructuring_assignment +--- +
{{jsSidebar("Operators")}}
+ +

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

+ +
{{EmbedInteractiveExample("pages/js/expressions-destructuringassignment.html", "taller")}}
+ + + +

構文

+ +
let 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 4(finished) 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}
+
+ +

解説

+ +

オブジェクトリテラルと配列リテラルは、いくつかのデータをアドホックにまとめる簡単な方法を提供します。

+ +
const x = [1, 2, 3, 4, 5];
+ +

分割代入は似たような構文を使用しますが、代入の左辺が元の変数からどの値を受け取るかを定義します。

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

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

+ +

+ +

配列の分割代入

+ +

簡単な例

+ +
const foo = ['one', 'two', 'three'];
+
+const [red, yellow, green] = foo;
+console.log(red); // "one"
+console.log(yellow); // "two"
+console.log(green); // "three"
+
+ +

宣言後の割り当て

+ +

変数は宣言とは別に、分割代入によって値を代入することができます。

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

既定値

+ +

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

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

変数の入れ替え

+ +

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

+ +

分割代入を使用せずに 2 つの値を交換するには、一時変数 (または、一部の低水準言語においては XOR 交換アルゴリズム) が必要です。

+ +
let a = 1;
+let b = 3;
+
+[a, b] = [b, a];
+console.log(a); // 3
+console.log(b); // 1
+
+const arr = [1,2,3];
+[arr[2], arr[1]] = [arr[1], arr[2]];
+console.log(arr); // [1,3,2]
+
+
+ +

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

+ +

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

+ +

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

+ +
function f() {
+  return [1, 2];
+}
+
+let a, b;
+[a, b] = f();
+console.log(a); // 1
+console.log(b); // 2
+
+ +

返値の無視

+ +

関心のない返値は無視することができます。

+ +
function f() {
+  return [1, 2, 3];
+}
+
+const [a, , b] = f();
+console.log(a); // 1
+console.log(b); // 3
+
+const [c] = f();
+console.log(c); // 1
+
+ +

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

+ +
[,,] = f();
+
+ +

配列の残余部分への変数の代入

+ +

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

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

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

+ +
const [a, ...b,] = [1, 2, 3];
+
+// SyntaxError: rest 要素の末尾にカンマがあってはなりません
+// 常に最後の要素として rest 演算子を使用してください。
+
+ +

正規表現の一致からの値取得

+ +

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

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

オブジェクトの分割代入

+ +

簡単な例

+ +
const user = {
+    id: 42,
+    is_verified: true
+};
+
+const {id, is_verified} = user;
+
+console.log(id); // 42
+console.log(is_verified); // true
+
+ +

宣言のない代入

+ +

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

+ +
let 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} と考えられるためです。

+ +

( ... ) の式の前にセミコロンが必要です。そうしなければ、前の行の関数を実行に使用される可能性があります。

+
+ +

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

+ +

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

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

ここで、例えば、const {p: foo} = o はオブジェクト o から p という名前のプロパティを取り、foo という名前のローカル変数へ代入します。

+ +

既定値

+ +

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

+ +
var {a = 10, b = 5} = {a: 3};
+
+console.log(a); // 3
+console.log(b); // 5
+ +

新しい変数名の割り当てとデフォルト値の提供

+ +

両方ともプロパティにすることができます

+ + + +
const {a: aa = 10, b: bb = 5} = {a: 3};
+
+console.log(aa); // 3
+console.log(bb); // 5
+
+ +

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

+ +
const user = {
+  id: 42,
+  displayName: 'jdoe',
+  fullName: {
+    firstName: 'John',
+    lastName: 'Doe'
+  }
+};
+
+function userId({id}) {
+  return id;
+}
+
+function whois({displayName, fullName: {firstName: name}}) {
+  return `${displayName} is ${name}`;
+}
+
+console.log(userId(user)); // 42
+console.log(whois(user));  // "jdoe is John"
+ +

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

+ +

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

+ +
function drawChart({size = 'big', coords = {x: 0, y: 0}, radius = 25} = {}) {
+  console.log(size, coords, radius);
+  // グラフの描画
+}
+
+drawChart({
+  coords: {x: 18, y: 30},
+  radius: 30
+});
+ +
+

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

+
+ +

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

+ +
const 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'
+};
+
+let {
+  title: englishTitle, // rename
+  translations: [
+    {
+       title: localeTitle, // rename
+    },
+  ],
+} = metadata;
+
+console.log(englishTitle); // "Scratchpad"
+console.log(localeTitle);  // "JavaScript-Umgebung"
+ +

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

+ +
const 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 (const {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"
+
+ +

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

+ +

オブジェクトリテラルのような計算されたプロパティの名前も分割代入で使用できます。

+ +
let key = 'z';
+let {[key]: foo} = {z: 'bar'};
+
+console.log(foo); // "bar"
+
+ +

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

+ +

Rest/Spread Properties for ECMAScript 提案 (ステージ 4) は、分割代入に 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 で有効ではない{{glossary("Identifier", "識別子")}}であるプロパティ名を分割代入で使用できます。

+ +
const foo = { 'fizz-buzz': true };
+const { 'fizz-buzz': fizzBuzz } = foo;
+
+console.log(fizzBuzz); // "true"
+
+ +

配列とオブジェクトの分割代入の組み合わせ

+ +

配列とオブジェクトの分割代入は組み合わせることができます。配列 props の 3 番目の要素にあるオブジェクトの name プロパティが欲しい場合、次の操作ができます。

+ +
const props = [
+  { id: 1, name: 'Fizz'},
+  { id: 2, name: 'Buzz'},
+  { id: 3, name: 'FizzBuzz'}
+];
+
+const [,, { name }] = props;
+
+console.log(name); // "FizzBuzz"
+
+ +

オブジェクトが分割されるときにはプロトタイプチェーンが参照される

+ +

オブジェクトが分割されるときで、自分自身のプロパティがアクセスされない場合は、プロトタイプチェーンを辿って参照が続けられます。

+ +
let obj = {self: '123'};
+obj.__proto__.prot = '456';
+const {self, prot} = obj;
+// self "123"
+// prot "456"(プロトタイプチェーンへのアクセス)
+ +

仕様

+ + + + + + + + + + + + +
仕様書
{{SpecName('ESDraft', '#sec-destructuring-assignment', 'Destructuring assignment')}}
+ +

ブラウザーの互換性

+ +
+ + +

{{Compat("javascript.operators.destructuring")}}

+
+ +

関連情報

+ + -- cgit v1.2.3-54-g00ecf