ES6 In Depth 는 ECMAScript 표준의 6번째 버전(이하 ES6) 에서 JavaScript 프로그래밍언어에 추가된 새로운 기능들에 대한 연속기획물 입니다.
Editor’s note: Firefox Developer Tools engineer Nick Fitzgerald에 의해 작성된, 오늘 포스팅의 이전 버전은 원래 Nick의 블로그에 Destructuring Assignment in ES6 라는 제목으로 게재되었습니다.
What is destructuring assignment?
Destructuring assignment 는 array 나 object 의 properties 를 literals 와 유사해보이는 구문을 사용하여 변수로 할당합니다. 이 구문은 극단적으로 간결한 반면, 전통적인 property 접근 보다 훨씬 더 명확해 보입니다.
destructuring assignment 없이는, 아마도 array 의 첫 세 아이템들에 아래와 같은 방식으로 접근할 것입니다:
var first = someArray[0];
var second = someArray[1];
var third = someArray[2];
destrucuring assignment 를 사용하면, 같은 코드가 더 간결하고 읽기 쉬워집니다:
var [first, second, third] = someArray;
SpiderMonkey (파이어폭스의 JavaScript 엔진) 는 이미 destructuring 대부분의 기능을 지원합니다, 그러나 완전히 모두는 아닙니다. SpiderMonkey’s destructuring (and general ES6) support in bug 694100을 살펴보세요.
Destructuring arrays and iterables
우리는 이미 위 배열에서 destructuring assignment 의 한가지 예를 보았습니다. 구문의 일반적인 형태는:
[ variable1, variable2, ..., variableN ] = array;
이것은 variable1 에서 variableN 까지에 그에 상응하는 배열 아이템을 할당합니다. 만약 동시에 변수들을 선언하기를 원한다면, var, let 또는 const를 변수 할당부 앞에 추가할 수 있습니다.
var [ variable1, variable2, ..., variableN ] = array;
let [ variable1, variable2, ..., variableN ] = array;
const [ variable1, variable2, ..., variableN ] = array;
사실상, 당신이 원하는 만큼 깊이 패턴을 중복할 수 있기 때문에, variable은 잘못된 호칭입니다:
var [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo);
// 1
console.log(bar);
// 2
console.log(baz);
// 3
게다가, destructured 되는 배열의 아이템들을 건너뛸 수 있습니다.
var [,,third] = ["foo", "bar", "baz"];
console.log(third);
// "baz"
그리고 “rest” 패턴으로 배열에 나열된 아이템들을 담을 수 있습니다.
var [head, …tail] = [1, 2, 3, 4];
console.log(tail);
// [2, 3, 4]
배열에서 out of bound(index가 넘어감) 또는 존재하지 않는 아이템에 접근할때, 배열 index 로 접근한 것과 같은 결과를 얻게 됩니다: undefined.
console.log([][0]);
// undefined
var [missing] = [];
console.log(missing);
// undefined
배열 할당 패턴의 destructuring assignment 는 iterable 하게 동작한다는 것은 기억해두세요:
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
Destructuring objects
객체에서의 destructuring 은 변수를 객체의 properties 에 bind 하도록 해줍니다. 당신은 bind 될 property 와 그 뒤에 값을 bind 할 변수를 지정합니다.
var robotA = { name: "Bender" };
var robotB = { name: "Flexo" };var { name: nameA } = robotA;
var { name: nameB } = robotB;console.log(nameA);
// "Bender"
console.log(nameB);
// "Flexo"
perperty 와 변수 이름(variable name)이 같은 경우, 유용한 단축 구문이 있습니다.
var { foo, bar } = { foo: "lorem", bar: "ipsum" };
console.log(foo);
// "lorem"
console.log(bar);
// "ipsum"그리고 배열에서의 destructuring 처럼, destructuring 을 중복 조합해서 사용할 수 있습니다:
var complicatedObj = {
arrayProp: [
"Zapp",
{ second: "Brannigan" }
]
};var { arrayProp: [first, { second }] } = complicatedObj;console.log(first);
// "Zapp"
console.log(second);
// "Brannigan"
정의되지 않은 properties 에 destructure 하면, undefined 를 얻게 됩니다:
var { missing } = {};
console.log(missing);
// undefined주의해야 할 부분은 그것들을(destructuring 할때 사용할 변수) 선언할때가 아닌(let, const 또는 var 없을때), 객체에 destructuring 을 사용할때 변수에 할당해야 한다는 것입니다.
{ blowUp } = { blowUp: 10 };
// Syntax error이것은 JavaScript 문법이 { 와 함께 시작하는 구문은 모두 block 구문(예를들면, { console } 는 유효한 블록 구문입니다.)으로서 파싱하라고 engine 에게 알려주기 때문에 발생합니다. 해결책은 괄호안으로 전체 표현을 둘러싸는 것입니다:
({ safe } = {});
// No errorsDestructuring values that are not an object, array, or iterable
null 이나 undefined 에 destructuring 을 사용하려고 시도하면 type error 를 얻게 됩니다:
var {blowUp} = null;
// TypeError: null has no properties그러나 booleans, numbers, and strings 와 같은 다른 원시(primitive)타입에는 destructure 할 수 있고, undefined를 얻습니다:
var {wtf} = NaN;
console.log(wtf);
// undefined이것은 예상치 못했을지도 모르지만, 원인은 단순한 합니다. 객체 할당 패턴을 사용할 때 destructure 되는 value 는 Object로 강제되어지는 것이 필수입니다. 모든 type 은 객체로 바뀔수 있으나, null 과 undefined 는 바뀌어질 수 없습니다. 배열 할당 패턴을 사용하는 경우, 값(value)은 interator 를 가지고 있어야만 합니다.
Default values
당신이 destructuring 하는 property 가 정의되지 않았을때, 기본값을 제공할 수 있습니다:
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(Editor’s note: 이 기능은 현재 세번째를 제외한 처음 두가지 경우만 Firefox 에 구현되었습니다. bug 932080를 보세요.)
Practical applications of destructuring
FUNCTION PARAMETER DEFINITIONS
개발자로서, 우리는 종종 API 사용자에게 다양한 parameters 의 순서를 기억하도록 강제하는 대신 여러개의 properties 와 함께 하나의 object 를 사용하도록 함으로써 좀 더 사용자 친화적인 API 를 만들 수 있습니다. properties 하나를 참조할때마다 이런 single parameter object 의 반복사용을 피하기 위해 destructuring 을 사용할 수 있습니다:
function removeBreakpoint({ url, line, column }) {
// ...
}이것은 Firefox DevTools JavaScript debugger 로부터 가져온 실무 코드를 단순하게 만든 snippet 입니다.
CONFIGURATION OBJECT PARAMETERS
이전 예제에서 확장해서, 우리가 destructuring 한 object의 properties에 default 값을 줄 수 있습니다. 이것은 설정 객체(configuration object)를 제공하거나 많은 객체의 properties 가 이미 적당한 기본값을 가지고 있을때 매우 유용합니다. 예를 들면, jQuery의 ajax 함수는 두번째 parameter로서 configuration object 를 가지며, 이렇게 재 작성될 수 있습니다:
jQuery.ajax = function (url, {
async = true,
beforeSend = noop,
cache = true,
complete = noop,
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};이렇게 설정 객체 각각의 property 를 위해 var foo = config.foo || theDefaultFoo; 를 반복하는 것을 피할 수 있습니다.
(Editor’s note: 불행히도, 단축 객체 구문과 함께하는 default values는 아직 Firefox에 구현되지 않았습니다. 제가 알기로, 우리는 그 중 작동하는(구현된) 몇몇 부분을 가지고 있습니다. bug 932080 의 최신 업데이트 부분을 보세요.)
WITH THE ES6 ITERATION PROTOCOL
우리가 이 시리즈에서 이미 논의해 왔듯이 ECMAScript 6 는 iteration protocol을 정의합니다. 당신이 Maps(an ES6 addition to the standard library)을 iterate 할때, 당신은 [key, value] 쌍을 얻게됩니다. 우리는 key 와 value 둘다에 쉽게 접근하기 위해서 이 한쌍을 destructure 할 수 있습니다:
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"keys 만 iterate:
for (var [key] of map) {
// ...
}또는 value 만 iterate:
for (var [,value] of map) {
// ...
}MULTIPLE RETURN VALUES
비록 multiple return value 는 언어상으로 만들 수 없지만, array 을 return 할 수 있고 결과를 destructure 할 수 있기 때문에 굳이 필요하지 않습니다.
function returnMultipleValues() {
return [1, 2];
}
var [foo, bar] = returnMultipleValues();대신, 당신은 container 로서 object를 사용할 수도 있고, 반환된 값에 이름을 붙일 수도 있습니다:
function returnMultipleValues() {
return {
foo: 1,
bar: 2
};
}
var { foo, bar } = returnMultipleValues();이러한 패턴 둘다 임시 container를 만드는 것보다 훨씬 더 낫습니다.
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) => ...);IMPORTING NAMES FROM A COMMONJS MODULE
ES6 모듈을 아직 써보지 않으셨나요? 여전히 CommonJS 모듈을 사용하고 있나요? 문제 없습니다! CommonJS module X를 import 할때, module X 가 당신이 의도한 것 보다 더 많은 기능들을 노출하는 것은 꽤 일반적인 부분입니다. destructuring 과 함께, 당신이 사용하려는 주어진 모듈의 일부에 대해 잘 알 수 있고, 당신의 namespace 를 어지럽히는 것을 피할 수 있습니다:
const { SourceMapConsumer, SourceNode } = require("source-map");(그리고 만약 당신이 ES6 모듈을 사용한다면, 당신은 import 선언에서 유사한 구문을 이용할 수 있다는 것을 알고 있을 겁니다.)
Conclusion
알다시피, destructuring 은 개인적으로도 많은 경우 유용합니다. Mozilla에서 우리는 그것들과 함께 많은 경험을 해왔습니다. Lars Hansen 은 JS destructuring 을 Opera 에서 10년 전에 소개했습니다, 그리고 얼마후에 Brendan Eich 는 Firefox 에 지원하기 시작했습니다. 그것은 Firefox 2에 탑재 되었습니다. 우리는 destructuring 이 언어를 사용하는 매일매일에 스며든 것을, 조용히 모든 장소에서 당신의 코드를 조금 더 짧고 깔끔하게 만들 것이란걸 알고 있습니다.
5주 전에, 우리는 ES6가 당신의 JavaScript 를 작성하는 방식을 바꿀거라고 이야기했습니다. 이것은 그런 종류의 기능입니다: 한번에 한가지씩 배울 수 있는 단순한 개선. 함께 할수록, 그것들이 당신이 작업하는 모든 프로젝트에 결국 영향을 미칠 것입니다. Revolution by way of evolution.
ES6를 준수하며 destructuring 을 개선하는 것은 팀의 노력으로 진행되어왔습니다. Tooru Fujisawa (arai) 와 Arpad Borsos (Swatinem) 의 기여에 감사합니다.
destructuring 기능 지원은 크롬을 위해 개발진행중이고, 다른 브라우저들도 당연히 조만간 추가 지원할 것입니다. 만약 당신이 웹에서 destructuring을 사용하길 원한다면, 지금 당신은 Babel or Traceur 를 사용할 필요가 있습니다.
이번주 포스팅을 해준 Nick Fitzgerald 에게 다시한번 감사드립니다.
다음주, 우리는 JS가 이미 가진, 작성이 손쉬워지는 것 외에는 특별할 것 없는 기능을 살펴볼 것입니다 — 기본적인 building blocks의 하나. 궁금한가요? 당신이 흥미있어하는 구문이 있나요? 나는 대답이 yes 일거라고 자신있게 예측합니다 , 다음주에는 ES6 arrow function 을 깊게 살펴보시죠.
Jason Orendorff
ES6 In Depth editor
발번역은 죄송 ;)
This work is licensed under the Creative Commons 저작자표시-동일조건변경허락 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.