[JavaScript] 구조 분해 / 비구조화 할당 (Destructuring assignment)

이 포스트에서는 ES6(ECMA2015) 문법인 구조 분해(비구조화) 할당에 대하여, 문법과 용례를 정리해보고자 합니다.

구조 분해 할당(Destructuring assignment) 구문은 배열이나 객체의 속성을 해체하여 그 값을 개별 변수에 담을 수 있게 하는 JavaScript 표현식입니다. - MDN

Destructuring. 일단 비구조화라는 표현보다 저는 구조 분해하는 표현이 더 와닿기 때문에, 저는 구조 분해 할당이라고 표기하도록 하겠습니다.(MDN도 그렇게 함..!!ㅎ)



기본 패턴

먼저, 구조 분해 할당은 구조 분해라는 말 그대로 구조화되어 있는 자료구조(array, object)를 분해해서, 내부 값들을 개별적인 변수들로 나누는 개념의 문법입니다.

이는 코드의 양을 줄여주고, 가독성을 향상시키는 이점이 있는데 예를 들어보도록 하겠습니다.


배열

1
2
3
4
5
6
7
// 일반적인 변수 할당
const numbers = [0, 1, 2];
const zero = numbers[0];
const one = numbers[1];
const two = numbers[2];

console.log(zero, one, two); // 0 1 2

일반적으로, 배열의 값들을 변수에 할당하고자 한다면 위와 같은 접근을 통해 할당 받을 수 있습니다.

예시의 경우 비교적 간단하지만, 할당 받아야하는 변수가 많아지고, 구조가 복잡하다면 꽤나 귀찮고 가독성이 떨어지는 코드가 될 여지가 있습니다.


이런 경우 구조 분해 할당을 사용하면, 아래와 같이 간략하게 코드를 작성할 수 있습니다.

1
2
3
4
// 구조 분해 할당
const numbers = [0, 1, 2];
const [zero, one, two] = numbers;
console.log(zero, one, two); // 0 1 2

그리고 배열의 인덱스 값에 따라, 선언한 변수 개수만큼 할당됩니다

1
2
const [zero, one] = numbers;
console.log(zero, one); // 0 1
1
2
const [zero, one, two, three] = numbers;
console.log(zero, one, two, three); // 0 1 2 undefined

객체

객체에서도 이와 유사하게 표현됩니다.

1
2
3
4
5
6
7
8
9
10
11
// 구조 분해 할당 (객체)
const numbers = {
zero: 0,
one: 1,
two: 2,
};
const { one, two, zero } = numbers;
console.log(zero, one, two); // 0 1 2

const { num1, num2, num3 } = numbers;
console.log(num1, num2, num3); // undefined undefined undefined

단, 배열과 달리 변수를 객체의 key값으로 하지 않는 경우, 원래 변수에서 어떤 값을 할당할지 컴파일러가 인식하지 못합니다.


그럼 못해..? 🥲

물론 가능합니다. 만약 원래 key값과는 다른 이름의 변수에 할당하고 싶다면, 아래와 같은 구문으로 할당할 수 있습니다.

1
2
const { zero: num1, one: num2, two: num3 } = numbers;
console.log(num1, num2, num3); // 0 1 2

왜 이럼…? 🤔

객체의 특징을 생각해보면, 객체는 내부 속성들의 순서가 존재하지 않기 때문에, key값과 이름이 동일하지 않으면 인식되지 않는 것입니다.

1
2
3
4
5
const { two, zero, one } = numbers;
// const { one, two, zero } = numbers;
// ...

console.log(zero, one, two); // 0 1 2
1
2
const { one, two } = numbers;
console.log(one, two); // 1 2

객체의 이런 특징 때문에, 객체는 구조 분해 할당을 할 때 위와 같이 순서를 바꾸던, 생략을 하던 문제없이 할당할 수 있습니다.



나머지(rest) 할당

이 부분의 경우 선행으로 ES6의 ... 문법, Spread 문법를 알아야 하는데,

전개 구문 - MDN

MDN 링크로 대체하고 추후 추가 포스팅을 할 계획입니다.


만약, 특정 분리할 몇몇 값들 빼고 나머지 배열 및 객체를 따로 하나의 변수에 유지하고 싶다거나 할 때 사용할 수 있는 방법입니다.


배열

1
2
3
4
5
const numbers = [0, 1, 2, 3, 4, 5, 6];
const [zero, one, two, ...rest] = numbers;

console.log(zero, one, two); // 0 1 2
console.log(rest); // [3, 4, 5, 6]

0,1,2 외의 나머지 값들이 rest라는 새로운 배열에 할당된 것을 볼 수 있습니다.


객체

객체또한 같은 의미로 사용할 수 있습니다.

1
2
3
4
5
const numbers = { zero: 0, one: 1, two: 2, three: 3, four: 4, five: 5, six: 6 };
const { zero, one, two, ...rest } = numbers;

console.log(zero, one, two); // 0 1 2
console.log(rest); // { three: 3, four: 4, five: 5, six: 6 }

나머지 할당을 사용할 때, 주의할 점은 나머지라는 의미처럼 마지막 요소로 할당하여야 합니다.

1
2
3
4
5
const numbers = [0, 1, 2, 3, 4, 5, 6];

// SyntaxError: Rest element must be last element
const [ zero, one, two, ...rest, six ] = numbers; // ❌
const [ zero, one, two, ...rest, ] = numbers; // ❌
1
2
3
4
5
const numbers = { zero: 0, one: 1, two: 2, three: 3, four: 4, five: 5, six: 6 };

// SyntaxError: Rest element must be last element
const { zero, one, two, ...rest, six } = numbers; // ❌
const { zero, one, two, ...rest, } = numbers; // ❌


기본값(Default values) 사용

기본값을 할당하여, 만약 분해한 값이 undefined라면, 기본값을 그 변수의 값으로 대신 사용합니다.


배열

아까 예제에서 배열의 index 너머의 값을 할당했더니, undefined로 값이 할당된 예제가 있었습니다.

그럴때 undefined로 인해 발생하는 에러를 방지하기 위해 사용할 수 있는 문법입니다.

1
2
3
const numbers = [0, 1, 2];
const [zero, one = 99, two, three = 3] = numbers;
console.log(zero, one, two, three); // 0 1 2 3

one = 99에서 볼 수 있듯이 undefined가 아니라면 기본값이 할당되지 않음


객체

1
2
3
const numbers = { zero: 0, one: 1, two: 2 };
const { zero, one = 99, two, three = 3 } = numbers;
console.log(zero, one, two, three); // 0 1 2 3


변수 값 교환하기

1
2
3
4
5
let a = 100;
let b = 500;

[a, b] = [b, a];
console.log(a, b); // 500, 100

원래 두 값을 교환하려면 대부분의 언어에서 임시 변수가 필요함

1
2
3
4
5
6
let a = 100;
let b = 500;
let temp = a;

a = b;
b = temp;


함수의 리턴 값 분해

1
2
3
4
5
6
function returnArray() {
return [1, 2];
}

let [one, two] = returnArray();
console.log(one, two); // 1 2
1
2
3
4
5
function returnObject() {
return { one: 1, two: 2 };
}
let { one, two } = returnObject();
console.log(one, two); // 1 2

위와 같이 더 간결하게 return받은 배열 및 객체를 활용할 수 있습니다.



일부 반환값 무시

1
2
3
4
5
6
7
8
9
function returnArray() {
return [1, 2, 3];
}

let [one, , three] = returnArray();
let [, ,] = returnArray();
let [num1] = returnArray();
console.log(one, three); // 1 3
console.log(num1); // 1

,(comma)를 이용해 자유자제로 필요하지 않은 반환 값을 무시할 수 있습니다.



호환성

IE를 제외한 모든 브라우저에서 사용가능합니다.



참고