구조분해 할당이란 무엇인가요?
구조 분해 할당을 사용하면 배열 또는 객체 리터럴과 유사한 구문을 사용하여 배열 및 객체 속성 값을 일련의 변수에 할당할 수 있습니다. 이 구문은 기존 속성 액세스보다 매우 간결하고 명확합니다.
구조 분해 할당을 사용하지 않고 배열의 처음 세 항목에 액세스:
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;
이렇게 하면 배열의 해당 항목이 변수1부터 변수N까지 순차적으로 할당됩니다. 동시에 변수를 선언해야 하는 경우 구조 분해 표현식 앞에 var, let 또는 const 키워드를 추가할 수 있습니다.
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"
Rest 표현식을 사용하여 배열의 나머지 항목을 캡처할 수도 있습니다.
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
객체의 구조 분해 할당을 사용할 때 또 다른 잠재적인 함정이 있습니다. 구조 분해 할당 중에 변수 선언(var, let 또는 const 키워드 없음)이 없다는 것입니다.
{ blowUp } = { blowUp: 10 }; // Syntax error { blowUp } = { blowUp: 10 }; // Syntax error
이는 JavaScript 구문이 엔진에 {로 시작하는 모든 명령문이 명령문 블록임을 알려주기 때문입니다(예: {console}은 법적 명령문 블록임). 해결 방법은 전체 명령문을 괄호 쌍으로 묶는 것입니다. 🎜>
({ 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 메소드의 두 번째 매개변수는 구성 객체이며 다음과 같이 구현할 수 있습니다.
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 };
반복자와 함께 사용
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;
function returnMultipleValues(k) { k(1, 2); } returnMultipleValues((foo, bar) => ...); function returnMultipleValues(k) { k(1, 2); } returnMultipleValues((foo, 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 的使用中,悄悄地使我们的代码更简短、整洁。