배열과 객체는 여러 개의 값을 다룰 때 유용하게 활용된다.
인덱스로 여러 값에 순서가 있는 배열과 프로퍼티 네임으로 여러 값에 이름이 붙는 객체의 구조가 서로 다르기 때문에 Destructuring 문법도 배열과 객체에 각각 적용되는 방식에 차이가 있다.
const rank = ['효준', '유나', '민환', '재하'];
const macbook = rank[0];// 효준
const ipad = rank[1];// 유나
const airpods = rank[2];// 민환
const coupon = rank[3];// 재하
console.log(macbook);
console.log(ipad);
console.log(airpods);
console.log(coupon);
이렇게 배열의 인덱스를 활용하면 혹시라도 도중에 순위가 변동되어서 배열 안의 요소들의 순서가 변경되었을 때 자연스럽게 배열의 순서에 따라 값이 할당된다.
Destructuring은 이런 상황에서 유용하게 활용되는데, 이렇게 한 줄로 표현이 가능해진다.
const rank = ['유나', '효준', '민환', '재하'];
const [macbook, ipad, airpods, coupon] = rank;
console.log(macbook);
console.log(ipad);
console.log(airpods);
console.log(coupon);
할당연산자 = 왼편에 변수의 이름이 배열의 형태로 선언되어 있고 그리고서 rank 배열 자체를 할당해 버린 것이다. 배열의 형태를 한 변수 이름들에 rank 배열의 요소들이 순서대로 할당되는 원리로 동작하는 것이다. 배열을 분해해서 하나씩 할당하는 원리라고 할 수 있다.
한 가지 주의할 점은 할당연산자 =의 오른쪽에 있는 값이 배열의 형식이 아니거나 혹은 아예 아무것도 할당하지 않으면 오류가 발생한다.
배열을 가지고 Destructuring을 할 때 꼭 선언된 변수의 개수와 배열의 길이가 같아야 할 필요는 없다. 만약 할당하는 배열의 길이가 좀 더 길더라도 그냥 인덱스에 따라 순서대로 할당이 되기 때문에 길이가 넘치는 요소는 어느 변수에도 할당되지 않는 것이다. 대신 이렇게 순서대로 할당되는 특징을 잘 고려해서 배열 안의 요소들의 순서나 혹은 할당 받을 변수들의 순서는 잘 정리 해야 된다.
가장 마지막 변수에 마침표 세 개(...)를 붙여주면 함수의 Rest Parameter처럼 배열을 분해해서 할당할 때 앞쪽에 있는 변수의 순서대로 요소를 할당하고 남은 나머지 요소를 마지막 변수의 배열로 할당하는 게 가능하다. Rest Parameter와 마찬가지로 항상 마지막 변수에만 활용할 수 있다. 반대로 할당하는 배열의 길이가 선언된 변수의 개수보다 적으면 순서대로 배열 안의 요소가 할당되고 남은 변수에는 undefined값이 할당된다. 그런데 여기서도 함수의 파라미터와 비슷하게 기본값을 작성할 수 있다.
const rank = ['유나', '효준', '민환'];
const [macbook, ipad, airpods, coupon = '없음'] = rank;
console.log(macbook); // 유나
console.log(ipad); // 효준
console.log(airpods); // 민환
console.log(coupon); // 없음
배열의 Destructuring 문법은 변수에 할당된 값을 서로 교환할 때도 활용할 수 있다.
let macbook = '효준';
let ipad = '유나';
console.log('MacBook 당첨자:', macbook);
console.log('iPad 당첨자:', ipad);
두 변수에 서로 다른 값이 할당되어 있는데 Destructuring 문법을 활용하지 않으면 이 두 변수의 값을 서로 교환할 때 임시로 값을 담아 둘 변수를 만들어서 macbook의 값을 담아두고 macbook에는 ipad의 값을 담고 ipad에는 temp에 있는 macbook의 값을 담는 방식으로 교환했었다.
let macbook = '효준';
let ipad = '유나';
console.log('MacBook 당첨자:', macbook);
console.log('iPad 당첨자:', ipad);
let temp = macbook;
macbook = ipad;
ipad = temp;
console.log('MacBook 당첨자:', macbook);
console.log('iPad 당첨자:', ipad);
그런데 이 코드에서 Destructuring 문법을 사용하게 되면
let macbook = '효준';
let ipad = '유나';
console.log('MacBook 당첨자:', macbook); // MacBook 당첨자: 효준
console.log('iPad 당첨자:', ipad); // iPad 당첨자: 유나
[macbook, ipad] = [ipad, macbook];
console.log('MacBook 당첨자:', macbook); // MacBook 당첨자: 유나
console.log('iPad 당첨자:', ipad); // iPad 당첨자: 효준
할당 연산자 =은 오른쪽 값을 왼쪽 피연산자에 할당하는 동작을 한다. 그래서 ipad에 담겨있는 "유나"가 macbook으로 할당되고 macbook에 담겨있는 "효준"이 ipad로 할당되게 된다.
객체도 배열과 크게 다르지 않지만 객체는 인덱스가 아니라 프로퍼티 네임으로 여러 값들을 구분한다. 점 표기법으로 매번 객체를 작성하지 않고 간결하게 프로퍼티 네임 자체를 변수처럼 사용하고자 할 때 Destructuring을 활용하게 된다.
const macbook = {
title: '맥북 프로 16형',
price: 3690000,
memory: '16GB',
storage: '1TB SSD 저장장치'
display: '16형 Retina 디스플레이',
};
const title = macbook.title;
const price = macbook.price;
console.log(title);
console.log(price);
이렇게 작성된 코드를 Destructuring 문법으로는
const macbook = {
title: '맥북 프로 16형',
price: 3690000,
memory: '16GB',
storage: '1TB SSD 저장장치'
display: '16형 Retina 디스플레이',
};
const {title, price} = macbook;
console.log(title);
console.log(price);
이렇게 작성할 수 있다. 배열을 보내야 할 떄는 배열처럼 대괄호로 감쌌던 것처럼 객체를 보내야 할 때도 객체처럼 중괄호로 변수를 감싸줘야 하는데, 요소를 인덱스 순서대로 할당했던 배열과는 다르게 객체는 프로퍼티 네임을 통해서 분해가 되기 때문에 할당 연산자 오른편의 객체에서 할당 연산자 왼편에 선언된 변수의 이름과 똑같은 프로퍼티 네임이 있으면 그 변수 이름에 값이 할당되는 방식으로 동작하는 것이다.
그 외에는 대부분 배열의 Destructuring 문법과 동일하게 동작한다. 만약 객체에 존재하지 않는 프로퍼티 네임으로 변수가 선언이 되어 있으면 undefined 값이 할당이 되고 할당 연산자를 통해서 기본값을 지정해 줄 수도 있다.
const { title, color = 'silver' } = macbook;
그리고 마침표 세 개를 통해서 변수를 선언하게 되면
const { title, ...rest } = macbook;
앞쪽에 프로퍼티가 유효한 부분들은 모두 할당한 다음에 남은 프로퍼티들을 하나의 객체로 모아서 변수에 담기는 모습을 확인할 수 있다. 나머지 프로퍼티를 하나의 객체로 모으는 방법을 제외하면 변수 이름은 항상 프로퍼티 네임과 똑같아야 할 필요는 없다.
const { title: product, ...rest } = macbook;
예를 들어 title이라는 프로퍼티를 title이라는 변수로 할당받지 않고 product라는 이름의 변수로 할당받고 싶다면 그럴 때는 프로퍼티 네임에 해당하는 title 다음에 :을 쓰고 내가 원하는 product를 작성해주면 프로퍼티 네임과 다른 새로운 이름의 변수를 선언할 수 있게 된다.
프로퍼티 네임이 일치하는 것을 찾아서 해당하는 값을 할당한다라고 이해해야 한다.
이렇게 새로운 이름으로 선언하는 방식이 꼭 필요한 경우가 있다. 간혹 객체 내부의 프로퍼티 네임이 변수 이름으로 사용할 수 없는 경우가 있다.
const macbook = {
title: '맥북 프로 16형',
price: 3690000,
memory: '16GB',
storage: '1TB SSD 저장장치'
display: '16형 Retina 디스플레이',
'serial-num': 'ABCDEFGHIJKL',
};
const { title: product, ...rest } = macbook;
이렇게 따옴표를 활용하면 중간에 - 하이픈 기호가 있어서 변수로는 사용할 수 없는 이름도 프로퍼티 네임으로 사용할 수 있게 된다.
const macbook = {
title: '맥북 프로 16형',
price: 3690000,
memory: '16GB',
storage: '1TB SSD 저장장치'
display: '16형 Retina 디스플레이',
'serial-num': 'ABCDEFGHIJKL',
};
const { title: product, 'serial-num': serialNum } = macbook;
이런 경우에는 Destructuring을 할 때 반드시 새로운 이름으로 변수를 선언해야 한다. 이뿐만 아니라 새로운 이름을 변수로 선언하는 방식은
const macbook = {
title: '맥북 프로 16형',
price: 3690000,
memory: '16GB',
storage: '1TB SSD 저장장치'
display: '16형 Retina 디스플레이',
'serial-num': 'ABCDEFGHIJKL',
};
const propertyName = 'title';
const { [propertyName] : product } = macbook;
이렇게 대괄호를 통해서 computed 프로퍼티 네임을 활용할 수도 있다.