代入の分割とは何ですか?
代入を分割すると、配列またはオブジェクトのリテラルと同様の構文を使用して、配列およびオブジェクトのプロパティ値を一連の変数に割り当てることができます。この構文は非常に簡潔で、従来のプロパティ アクセスよりも明確です。
構造化代入を使用せずに配列の最初の 3 つの項目にアクセスします:
var first = someArray[0]; var second = someArray[1]; var third = someArray[2]; var first = someArray[0]; var second = someArray[1]; var third = someArray[2];
分割代入を使用すると、対応するコードがより簡潔で読みやすくなります。
var [first, second, third] = someArray; var [first, second, third] = someArray;
SpiderMonkey (Firefox の JavaScript エンジン) はすでに、代入の構造化のほとんどの機能をサポートしていますが、完全にはサポートしていません。
配列と反復可能なオブジェクトの代入の構造化
上で配列の構造化代入の例を見てきましたが、この構文の一般的な形式は次のとおりです。
[ variable1, variable2, ..., variableN ] = array; [ variable1, variable2, ..., variableN ] = array;
var [ variable1, variable2, ..., variableN ] = array; let [ variable1, variable2, ..., variableN ] = array; const [ variable1, variable2, ..., variableN ] = array; var [ variable1, variable2, ..., variableN ] = array; let [ variable1, variable2, ..., variableN ] = array; const [ variable1, variable2, ..., variableN ] = array;
実際には、任意の深さにネストできます:
var [foo, [[bar], baz]] = [1, [[2], 3]]; console.log(foo); // 1 console.log(bar); // 2 console.log(baz); // 3 var [foo, [[bar], baz]] = [1, [[2], 3]]; console.log(foo); // 1 console.log(bar); // 2 console.log(baz); // 3
var [,,third] = ["foo", "bar", "baz"]; console.log(third); // "baz" var [,,third] = ["foo", "bar", "baz"]; console.log(third); // "baz"
var [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4] var [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4]
console.log([][0]); // undefined var [missing] = []; console.log(missing); // undefined console.log([][0]); // undefined var [missing] = []; console.log(missing); // undefined
function* fibs() { var a = 0; var b = 1; while (true) { yield a; [a, b] = [b, a + b]; } } var [first, second, third, fourth, fifth, sixth] = fibs(); console.log(sixth); // 5 function* fibs() { var a = 0; var b = 1; while (true) { yield a; [a, b] = [b, a + b]; } } var [first, second, third, fourth, fifth, sixth] = fibs(); console.log(sixth); // 5
オブジェクトの代入を分割しています
オブジェクトの構造化代入を使用すると、変数をオブジェクトのさまざまなプロパティ値にバインドできます。バインドするプロパティの名前を指定し、その後にバインドする変数を指定します:
var robotA = { name: "Bender" }; var robotB = { name: "Flexo" }; var { name: nameA } = robotA; var { name: nameB } = robotB; console.log(nameA); // "Bender" console.log(nameB); // "Flexo" var robotA = { name: "Bender" }; var robotB = { name: "Flexo" }; var { name: nameA } = robotA; var { name: nameB } = robotB; console.log(nameA); // "Bender" console.log(nameB); // "Flexo"
var { foo, bar } = { foo: "lorem", bar: "ipsum" }; console.log(foo); // "lorem" console.log(bar); // "ipsum" var { foo, bar } = { foo: "lorem", bar: "ipsum" }; console.log(foo); // "lorem" console.log(bar); // "ipsum"
var complicatedObj = { arrayProp: [ "Zapp", { second: "Brannigan" } ] }; var { arrayProp: [first, { second }] } = complicatedObj; console.log(first); // "Zapp" console.log(second); // "Brannigan" var complicatedObj = { arrayProp: [ "Zapp", { second: "Brannigan" } ] }; var { arrayProp: [first, { second }] } = complicatedObj; console.log(first); // "Zapp" console.log(second); // "Brannigan"
var { missing } = {}; console.log(missing); // undefined var { missing } = {}; console.log(missing); // undefined
{ blowUp } = { blowUp: 10 }; // Syntax error { blowUp } = { blowUp: 10 }; // Syntax error
({ safe } = {}); // No errors ({ safe } = {}); // No errors
その他の状況
null または未定義を構造解除しようとすると、型エラーが発生します:
var {blowUp} = null; // TypeError: null has no properties var {blowUp} = null; // TypeError: null has no properties
var {wtf} = NaN; console.log(wtf); // undefined var {wtf} = NaN; console.log(wtf); // undefined
デフォルト値
var [missing = true] = []; console.log(missing); // true var { message: msg = "Something went wrong" } = {}; console.log(msg); // "Something went wrong" var { x = 3 } = {}; console.log(x); // 3 var [missing = true] = []; console.log(missing); // true var { message: msg = "Something went wrong" } = {}; console.log(msg); // "Something went wrong" var { x = 3 } = {}; console.log(x); // 3
実際の応用
関数パラメータ
function removeBreakpoint({ url, line, column }) { // ... } function removeBreakpoint({ url, line, column }) { // ... }
構成オブジェクト
上記の例を改善するには、構造化されるオブジェクトのプロパティにデフォルト値を指定できます。多くの構成項目には適切なデフォルト値があるため、これは構成パラメータとして使用されるオブジェクトにとって非常に実用的です。たとえば、jQuery の ajax メソッドの 2 番目のパラメーターは構成オブジェクトであり、次のように実装できます。
jQuery.ajax = function (url, { async = true, beforeSend = noop, cache = true, complete = noop, crossDomain = false, global = true, // ... more config }) { // ... do stuff }; jQuery.ajax = function (url, { async = true, beforeSend = noop, cache = true, complete = noop, crossDomain = false, global = true, // ... more config }) { // ... do stuff };
反復子とともに使用されます
Map オブジェクトを走査するとき、分割代入を使用して [key, value] を走査できます:
var map = new Map(); map.set(window, "the global"); map.set(document, "the document"); for (var [key, value] of map) { console.log(key + " is " + value); } // "[object Window] is the global" // "[object HTMLDocument] is the document" var map = new Map(); map.set(window, "the global"); map.set(document, "the document"); for (var [key, value] of map) { console.log(key + " is " + value); } // "[object Window] is the global" // "[object HTMLDocument] is the document"
for (var [key] of map) { // ... } for (var [key] of map) { // ... } 只遍历值: for (var [,value] of map) { // ... } for (var [,value] of map) { // ... }
配列を返し、構造化代入によって戻り値を抽出します:
function returnMultipleValues() { return [1, 2]; } var [foo, bar] = returnMultipleValues(); function returnMultipleValues() { return [1, 2]; } var [foo, bar] = returnMultipleValues();
function returnMultipleValues() { return { foo: 1, bar: 2 }; } var { foo, bar } = returnMultipleValues(); function returnMultipleValues() { return { foo: 1, bar: 2 }; } var { foo, bar } = returnMultipleValues();
function returnMultipleValues() { return { foo: 1, bar: 2 }; } var temp = returnMultipleValues(); var foo = temp.foo; var bar = temp.bar; function returnMultipleValues() { return { foo: 1, bar: 2 }; } var temp = returnMultipleValues(); var foo = temp.foo; var bar = temp.bar;
导入 CommonJS 模块的指定部分
还没使用过 ES6 的模块吧,那至少使用过 CommonJS 吧。当导入一个 CommonJS 模块 X 时,模块提供的方法也许多余你实际使用的。使用解构赋值,你可以明确指定你需要使用模块的哪些部分:
const { SourceMapConsumer, SourceNode } = require("source-map"); const { SourceMapConsumer, SourceNode } = require("source-map");
如果你使用 ES6 的模块机制,你可以看到 import 声明时有一个类似的语法。
结论
我们看到,解构赋值在很多场景下都很实用。在 Mozilla,我们已经有很多经验。Lars Hansen 在 10 年前就向 Opera 引入了解构赋值,Brendan Eich 在稍微晚点也给 Firefox 添加了支持,最早出现在 Firefox 2 中。因此,解构赋值已经渗透到我们每天对 JS 的使用中,悄悄地使我们的代码更简短、整洁。