비구조화 할당 (Destructuring Assignment)
ES5에서는 구조화된 데이터를 변수로 받기 위해 아래와 같이 처리해야 했다.
// browser
var data = $('body').data(), // data has properties house and mouse
house = data.house,
mouse = data.mouse
// Node.js
var jsonMiddleware = require('body-parser').json
var body = req.body, // body has username and password
username = body.username,
password = body.password
하지만 ES6에서는 비구조화 할당을 사용해 아래와 같이 처리할 수 있다.
var {house, mouse} = $('body').data() // we'll get house and mouse variables
var {jsonMiddleware} = require('body-parser')
var {username, password} = req.body
주의할 점은 var로 할당하려는 변수명과 구조화된 데이터의 property명이 같아야 한다. 또한 구조화된 데이터가 아니라 배열의 경우 {}
대신 []
를 사용해서 위와 유사하게 사용할 수 있다.
var [col1, col2] = $('.column'),
[line1, line2, line3, , line5] = file.split('\n')
Destructring of nested object
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let body = { "userid":"da91love", "password":"1234567890", "site":{ "naver":"blog.naver.com", "tistory":"valuefatory" } } const {userid,site:{naver}} = body; console.log(userid); console.log(naver); const [c, ,d] = [1, 2, 3]; console.log(c); // 1 console.log(d); // 3 | cs |
위의 예에서 site안에 들어있는 naver을 해체 하고 싶은 경우, 중괄호{}로 감싸서 site{naver}로 해체하면 된다.
이때 한가지 주의할점은, 배열은 순서가 있기 때문에 꼭 순서대로 해체해야 원하는 값을 얻을 수 있지만, 객체는 순서가 정해지지 않기 때문에 순서를 꼭 지킬 필요가 없다.
이것이 무슨 말인가하면...
body의 객체는 userid,password,site순인데
site의 naver 값을 얻기 위해
const {userid, ,site:{naver}} = body;할 필요가 없다는 것이다.
default value for destructuring
-https://medium.com/@pyrolistical/destructuring-nested-objects-9dabdd01a3b8
1 2 3 4 | let foo = {}; const { prop1 = {} } = foo const { prop2 = {} } = foo | cs |
foo가 비어있는 객체이기 때문에, prop1은 undefined가 되고, prop1에는 default 값인 {}가 들어가게 된다.
이제 아래부터 문제가 되기 시작하는데..
1 2 3 4 5 6 | const user = { id: 339, name: 'Fred', age: 42 }; const {education: {degree}} = user; // TypeError: Cannot match against 'undefined' or 'null'. | cs |
education객체 아래에는 degree프로퍼티가 존재하지 않고 디폴트 값도 설정되어 있지 않기 때문에 타입에러가 발생한다.
그럼 이 문제도 위에서 처럼 디폴트값에 무언가를 주면 해결되지 않으려나 했는데...
1 2 3 4 5 6 7 | const user = { id: 339, name: 'Fred', age: 42 }; const {education: {degree} = {}} = user; console.log(degree); //prints: undefined | cs |
타입에러가 발생하진 않았지만 우리의 기대치인 {}와는 다른 undefined의 값이 나온다...
아.. 왜이럴까.
아래의 코드가 해결책.
1 2 3 4 5 6 7 | const user = { id: 339, name: 'Fred', age: 42 }; const {education: {degree} = {degree:{}}} = user; console.log(degree); //{} | cs |
user객체에는 education도 degree도 존재하지 않기 때문에, 어떤 네스팅 오브젝트에 {}값을 할당할 것인지 지정해주어야 한다..
만약 네스팅이 한번 더 해지면 어떨까.
1 2 3 4 5 6 | const user = { id: 339, name: 'Fred', age: 42 }; const {education: {school: {name}} = {}} = user; // TypeError: Cannot match against 'undefined' or 'null'. | cs |
위의 코드는 물론 에러를 유발한다.
아래가 해결책
1 2 3 4 5 6 | const user = { id: 339, name: 'Fred', age: 42 }; const {education: {school: {name}} = {shcool:{name:{}}}} = user; | cs |
구문
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
// 제안 3단계(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
변수 값 교환하기
하나의 비구조화 표현식만으로 두 변수의 값을 교환할 수 있습니다.
비구조화 할당 없이 두 값을 교환하려면 임시 변수(또는 일부 저-레벨 언어에서는 XOR-swap 트릭)가 필요합니다.
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
함수에서 반환된 배열 파싱
함수가 배열을 반환하는 경우가 있습니다. 비구조화는 반환된 배열 값을 통하여 작업을 더 간결하게 할 수 있습니다.
아래 예제에서, f() 함수
는 그 출력으로 배열 [1, 2]
을 반환하는데, 단 한 줄의 비구조화 구문으로 그 배열을 파싱할 수 있습니다.
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();
변수에 배열의 나머지를 할당하기
배열을 비구조화할 경우, rest 패턴을 이용해 해체하고 남은 부분을 하나의 변수에 할당할 수 있습니다.
var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
rest 요소의 오른쪽 뒤에 콤마가 있으면 SyntaxError
가 발생할 것입니다.
var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma
정규식과 일치하는 값 해체하기
정규식의 exec()
메서드는 일치하는 부분를 찾으면 그 문자열에서 정규식과 일치하는 부분 전체를 배열의 맨 앞에, 그리고 그 뒤에 정규식에서 괄호로 묶인 각 그룹과 일치하는 부분을 포함하는 배열을 반환합니다. 비구조화 할당은 필요하지 않은 경우 일치하는 전체 부분은 무시하고 필요한 부분만 쉽게 빼올 수 있습니다.
var url = "https://developer.mozilla.org/en-US/Web/JavaScript";
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
console.log(parsedURL); // ["https://developer.mozilla.org/en-US/Web/JavaScript", "https", "developer.mozilla.org", "en-US/Web/JavaScript"]
var [, protocol, fullhost, fullpath] = parsedURL;
console.log(protocol); // "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});
새로운 변수 이름으로 할당하기
객체로부터 속성을 해체하여 객체의 원래 속성명과는 다른 이름의 변수에 할당할 수 있습니다.
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
기본값 갖는 새로운 이름의 변수에 할당하기
새로운 변수명 할당과 기본값 할당을 한번에 할 수 있습니다.
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);
// 이제 드디어 차트 그리기 수행
}
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);
// 차트 그리기 수행
}
drawES2015Chart({
cords: { x: 18, y: 30 },
radius: 30
});
중첩된 객체 및 배열의 비구조화
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"
for of 반복문과 비구조화
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: 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"
이 예제는 user 객체로부터 id
, displayName
및 firstName
을 해체해 출력합니다.
계산된 속성 이름과 비구조화
계산된 속성 이름(computed property name)은, 객체 리터럴과 비슷하게 비구조화에도 사용될 수 있습니다.
let key = "z";
let { [key]: foo } = { z: "bar" };
console.log(foo); // "bar"
객체 비구조화에서의 Rest
Rest/Spread Properties for ECMAScript 제안(stage 3)에서는 비구조화에 rest 구문을 추가하고 있습니다. rest 속성은 비구조화 패턴으로 걸러지지 않은 열거형 속성의 키를 가진 나머지 항목들을 모읍니다.
let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40}
a; // 10
b; // 20
rest; // { c: 30, d: 40 }
속성 이름이 유효한 자바스크립트 식별자명이 아닌 경우
비구조화는 자바스크립트 식별자명으로 적합하지 않은 속성명이 제공된 경우에도 이용할 수 있습니다. 이때는 대체할 유효한 식별자명을 제공해야 합니다.
const foo = { 'fizz-buzz': true };
const { 'fizz-buzz': fizzBuzz } = foo;
console.log(fizzBuzz); // "true"
'C Lang > JS Basic' 카테고리의 다른 글
[ES6]기본 매개 변수 (Default Parameters) (0) | 2018.08.21 |
---|---|
[ES6]Class (0) | 2018.08.21 |
let과 const의 성질, 블록스코프, 블록스코프와 let, const, temporal dead zone (0) | 2018.08.20 |
Object.assign:객체를 병합 (0) | 2018.05.31 |
javascript class(class정의, 함수선언과 클래스선언의 차이, constructor, static메서드, extends,..) (0) | 2018.05.14 |