...
정의
'비구조화 할당(destructuring assignment) 구문은 배열이나 객체의 속성을 해체하여
그 값을 개별 변수에 담을 수 있게 하는 자바스크립트 표현식(expression)'입니다.
간단하게 정리하면 배열 [], 혹은 객체 {} 안의 값을 편하게 꺼내 쓸 수 있는 문법입니다.
기본 문법 - 배열
var [a1, a2, ...rest_a] = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(a1); // 1
console.log(a2); // 2
console.log(rest_a); // [3, 4, 5, 6, 7, 8, 9]
좌항이 호출될 변수명 집합, 우항이 할당할 값 입니다.
좌항의 각 요소에는 같은 index를 가지는 배열값이 할당됩니다.
또한 전개 연산자( ... )를 사용하여 좌항에서 명시적으로 할당되지 않은 나머지 배열 값들을 사용할 수 있습니다.
그리고 var, let, const를 사용해 변수들의 유효 범위를 명시적으로 선언할 수 있습니다.
💡 임의의 인덱스 값만 가져오기
cons arr = [1,2,3,4,5];
const [x,y,,,z] = arr;
console.log(x); // 1
console.log(y); // 2
console.log(z); // 5
🚨 전개 연산자 이후에 변수를 입력하거나, 좌 우항이 다른 속성일 경우 에러가 발생합니다.
[a1, a2, ...rest_a, a3] = [1, 2, 3, 4, 5, 6, 7, 8, 9]; // error
[a1, a2, ...rest_a] = {a1 : 10, a2: 20}; // error
기본 문법 - 객체
var { a1, a2, ...rest_a } = { a1 : 10, a2 : 20, a3 : 30, a4 : 40 };
console.log(a1); // 10
console.log(a2); // 20
console.log(rest_a); // { a3: 30, a4: 40 }
객체의 경우에는 우항의 key 값이 좌항의 변수명과 매칭됩니다.
배열과 마찬가지로 var, let, const가 적용 가능합니다.
💡 key이름 대신 다른 이름으로 변수명 사용하기
원래의 key 값과 다른 이름의 변수를 사용하는 방법은 아래와 같습니다.
* 윗 처럼 a1 대신 awesome_name이라는 value값을 변수로 사용합니다.
var { a1 : awesome_name, a2 : dumb , ...rest_a } = { a1 : 10, a2 : 20, a3 : 30, a4 : 40 };
console.log(awesome_name); // 10
console.log(dumb); // 20
console.log(a1); // Error : a1 is not defined
나머지 값을 뜻하는 전개 연산자는 우항의 key에 영향을 받지 않기 때문에 ...rest_a : blah 와 같은 표현식은 무의미하며, 실제로 에러가 발생합니다.
또한 우항의 key값에 변수명으로 사용 불가능한 문자열이 있을경우 아래와 같은 방식으로 비구조화 할 수 있습니다.
'it is key' 같은경우 key값으로서는 문자열이니 상관없지만, 변수명으로서는 사용 못하기 때문입니다.
var key = 'it is key'; //띄어쓰기 문자열 일경우 변수로 사용 못한다.
var { 'an-apple':apple, [key]:is_key } = { 'an-apple' : 10, 'it is key' : 20};
console.log(apple); // 10
console.log(is_key); // 20
💡 중첩된 객체 꺼내오기
const example = { a : 13, b : { C : 135, d : 146 } };
const { a, b : { d } } = example;
console.log(a); // 13
console.log(d); // 146
🚨 this가 있는 객체 메서드를 구조분해로 꺼내면 문제가 발생합니다!
왜냐하면 구조분해는 객체값을 복사해서 넣는것이기 때문입니다. 그래서 getCandy메서드 내용이 복사되어 구조분해 되니 그안의 this는 windows를 가리키게 됩니다.
var candyMachine = {
status : {
name : 'node',
count : 5,
},
getCandy() {
this.status.count--;
return this.status.count;
}
}
candyMachine.getCandy();
var count = candyMachine.status.count;
console.log(count); // 5-- 되서 4가 된다.
var { getCandy, status: { count } } = candyMachine;
getCandy();
console.log(count); // 여전히 4가 된다.
마지막으로 객체 비구조화에서 주의해야 할 점은
변수 선언에 대한 명시(var, let, const)가 없을 경우 괄호를 사용하여 묶어주어야 한다는 것 입니다.
({ a, b } = { a : 10, b : 20});
console.log(a); // 10
console.log(b); // 20
{ c, d } = { c : 30, d : 40}; // error
기본값 할당
비구조화의 범위를 벗어나는 값 할당을 시도하면 undefined를 반환하게 됩니다.
이런 경우를 방어하기 위해 변수명들에 할당 연산자(=)를 사용하여 기본값 할당을 할 수 있습니다.
[a, b] = [10];
console.log(a); // 10
console.log(b); // undefined
var {c = 30, d : new_name = 40} = { };
console.log(c); // 30
console.log(new_name); // 40
복사(copy)
var arr = [1,2,3];
var copy1 = arr; // 레퍼런스 이어붙이기
var [...copy2] = arr; // 값을 아예 복사
var copy3 = [...arr]; // ''
arr[0] = 'String';
console.log(arr); // [ 'String', 2, 3 ]
console.log(copy1); // [ 'String', 2, 3 ]
console.log(copy2); // [ 1, 2, 3 ]
console.log(copy3); // [ 1, 2, 3 ]
얕은 복사인 copy1은 arr을 참조하기 때문에 0번 요소가 변경되었지만
전개 연산자를 사용한 copy2, copy3는 깊은 복사가 된 것을 볼 수 있습니다.
객체 역시 전개 연산자로 깊은 복사를 사용할 수 있습니다.
무엇보다도 강력한 점은 복사와 함께 새로운 값을 할당할 수 있다는 점 입니다.
var prevState = {
name: "yuddomack",
birth: "1996-11-01",
age: 22
};
var state = {
...prevState,
age: 23
};
console.log(state); // { name: 'yuddomack', birth: '1996-11-01', age: 23 }
위와 같이 ...prevState를 사용하여 기존 객체를 복사함과 동시에 age키에 새로운 값(23)을 할당할 수 있습니다.
리액트의 props나 state처럼 이전 정보를 이용하는 경우 유용하게 사용할 수 있습니다.
이번엔 객체의 깊숙한 곳에 들어있는 값을 꺼내는 방법을 알아봅시다.
예를들어서 다음과 같은 객체가 있다고 가정해봅시다.
const deepObject = {
state: {
information: {
name: 'velopert',
languages: ['korean', 'english', 'chinese']
}
},
value: 5
};
여기서, name, languages, value 값들을 밖으로 꺼내주고 싶다면 어떻게 해야 할까요?
const deepObject = {
state: {
information: {
name: 'velopert',
languages: ['korean', 'english', 'chinese']
}
},
value: 5
};
const { name, languages } = deepObject.state.information;
const { value } = deepObject;
const extracted = {
name, // name : name, 같이 key와 value의 식별자가 같으면 하나로 생략 가능
languages,
value
};
console.log(extracted); // {name: "velopert", languages: Array[3], value: 5}
그런데 잠깐! 지금 extracted 객체를 선언 할 때 이런식으로 했는데요
const extracted = {
name,
languages,
value
}
이 코드는 다음 코드와 똑같습니다.
const extracted = {
name: name,
languages: languages,
value: value
}
만약에 key 이름으로 선언된 값이 존재하다면, 바로 매칭시켜주는 문법입니다.
이 문법은 ES6 의 object-shorthand 문법이라고 부릅니다.
함수에서의 사용
함수의 파라미터 부분에서도 비구조화 할당을 사용할 수 있습니다.
이러한 문법은 특히 API 응답 값을 처리하는데에 유용하게 사용됩니다.
function renderUser({name, age, addr}){
// 객체자체를 아규먼트로 받아올때 사용하면 좋다.
// 굳이 객체변수를 받아와서 일일히 풀어서 쓰는것보다, 직관적이게 아규먼트를 명시하는게 가독성면에서 좋다.
console.log(name);
console.log(age);
console.log(addr);
}
const users = [
{name: 'kim', age: 10, addr:'kor'},
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
];
users.map((user) => {
renderUser(user);
});
마찬가지로 map함수의 파라미터에도 바로 사용할 수 있습니다.
const users = [
{name: 'kim', age: 10, addr:'kor'},
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
];
users.map(({name, age, addr}) => {
console.log(name);
console.log(age);
console.log(addr);
});
클래스에서의 활용
class Person {
constructor({name, age}) {
this.name = name;
this.age = age;
}
introduce() {
return `제 이름은 ${this.name}입니다.`
}
}
class Student extends Person {
constructor({grade, ...rest}) {
// 부모 클래스의 생성자를 호출할 수 있습니다.
super(rest);
this.grade = grade;
}
introduce() {
// 부모 클래스의 `introduce` 메소드를 호출할 수 있습니다.
return super.introduce() + ` 저는 ${this.grade}학년입니다.`;
}
}
const s = new Student({grade: 3, name: '윤아준', age: 19});
s.introduce(); // 제 이름은 윤아준입니다. 저는 3학년입니다.
for of 문
const users = [
{name: 'kim', age: 10, addr:'kor'},
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
];
for(var {name : n, age : a} of users){
console.log(n);
console.log(a);
}
중첩된 객체 및 배열의 비구조화
const kim = {
name: 'kim',
age: 10,
addr: 'kor',
friends: [
{name: 'joe', age: 20, addr:'usa'},
{name: 'miko', age: 30, addr:'jp'}
]
};
var { name: userName, friends: [ ,{ name: jpFriend }] } = kim;
console.log(userName); // kim
console.log(jpFriend); // miko
Reference
https://learnjs.vlpt.us/useful/06-destructuring.html
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.