구조 분해 할당이란 무엇인가
2023 / 12 / 28 (목)
구조 분해 할당(Destructuring assignment)이란 배열 또는 객체의 값을 말 그대로 분해해 개별 변수에 즉시 할당하는 것을 의미한다.
배열과 객체에서 사용하며, 주로 어떠한 객체나 배열에서 선언문 없이 즉시 분해해 변수를 선언하고 할당하고 싶을 때 사용한다.
리액트 개발자라면 다음과 같은 형식의 코드를 useState에서 많이 봤을 것이다.
<script>
const array = [1,2,3,4,5]
const [first, second , third, ...arrayRest] = arry
// first 1
// second 2
// third 3
// arrayRest[4,5]
</script>
useState 함수는 2개 짜리 배열을 반환하는 함수이며, 첫 번째 값을 value로, 두 번째 값을 setter로 사용 가능하다.
useState가 객체가 아닌 배열을 반환하는 이유는 무엇일까?
배열의 구조 분해 할당은 자유롭게 이름을 선언할 수 있기 때문에 useState는 배열을 반환하는 것으로 추측할 수 있다고한다.
배열의 구조 분해 할당은 ,의 위치에 따라 값이 결정된다고한다.
따라서 앞의 예제에서 중간 인덱스에 대한 할당을 생략하고 싶다면 다음과 같이 선언할 수 있다.
<script>
const array = [1,2,3,4,5]
const [first, , , , fifth] = arry
// 2 , 3 , 4는 아무런 표현식이 없으므로 변수 할당이 생략 돼 있다.
// first 1
// fifth 5
</script>
이러한 방법은 실수를 유발할 가능성이 커서 일반적으로 배열의 길이가 작을 때 주로 쓰인다고한다.
배열 분해 할당에는 기본값을 선언할 수도 있다. 만약 사용하고자 하는 배열의 길이가 짧거나 값이 없는 경우에는 (undefined)기본값을 사용할 것이다.
<script>
const arry = [1, 2]
const [a = 10, b = 10, c= 10] = array
// a 1
// b 2
// c 10
</script>
한 가지 주의할 것은 반드시 undefined일 때만 기본값을 사용한다는 것이다.
<script>
const [a = 1, b =1, c = 1, d = 1, e =1] = [undefined , null, 0, '']
// a 1
// b null
// d ''
// e 1
</script>
위 배열 구조 분해 할당에서 기본값을 사용하는 것은 ,a와 e뿐이다. 자바스크립트에서 기본값을 사용할 수 있는 경우 undefined일 때뿐이다. 여기서 a는 명시적으로 undefined가 지정돼 있고, e의 경우에는 배열의 길이를 넘어서서 구조 분해 할당됐으므로 undefined로 평가되어 기본값이 할당된다.
특정값 이후의 값을 다시금 배열로 선언하고 싶다면 뒤이어 소개할
전개 연산자(spread operator)인 ...을 사용할 수도 있다.
<script>
const array = [1, 2, 3, 4, 5]
const [first, ...rest] = array
// first 1
// rest [2, 3, 4, 5]
</script>
뒤에 ...을 사용하면 나머지 모든 값을 해당 변수에 배열로 넣게 된다.
이는 어디서부터 어디까지 할당할지 예측할 수 있는 뒤쪽에서만 가능하다. 만약
앞쪽이라면 이를 파악할 수 없기 때문에 앞에서 전개 연산자를 사용하는 것은 불가능하다.
이러한 배열 구조 분해 할당 코드가 바벨에서 어떻게 트랜스파일(변환)되는지 살펴보자.
<script>
// 변환 전
const array = [1, 2, 3, 4, 5]
const [first, second, third ...arratRest] = array
// 변환 후
var array = [1, 2, 3, 4, 5]
var first = array[0],
second = array[1],
third = array[2],
arrayRest = array.slice(3)
</script>
구조 분해 할당을 단순히 배열에서 꺼내 오거나 slice해서 값을 할당하는 것을 볼 수 있다.
배열 구조 분해 할당 이전에는 선언을 4줄에 걸쳐서 했지만 구조 분해 할당 덕분에 이러한 작업을 단 한줄로 처리할 수 있게 됐다.
객체 구조 분해 할당은 말 그대로 객체에서 값을 꺼내온 뒤 할당하는 것을 의미한다.
배열 구조 분해 할당과는 달리, 객체는 내부 이름으로 꺼내온다는 차이가 있다.
<script>
const obj = {
a : 1,
b : 1,
c : 1,
d : 1,
e : 1,
}
const { a, b, c, ...objRest } = obj
// a 1
// b 2
// c 3
// objRest = { d: 1, e: 1 }
</script>
이를 새로운 이름으로 다시 할당하는 것 또한 가능하다.
<script>
const obj = {
a: 1,
b: 1,
}
const { a: first, b: second } = obj
// first 1
// second 2
</script>
배열과 마찬가지로 기본값을 주는 것도 가능하다.
<script>
const obj = {
a:1,
b:1,
}
const { a = 10, b = 10, c = 10 } = obj
//a 1
//b 1
//c 10
</script>
이러한 방식은 리액트 컴포넌트인 props에서 값을 바로 꺼내올 때 매우 자주 쓰는 방식이기 때문에 반드시 이해하고 있어야 한다.
<script>
function SampleComponent({ a,b }) {
return a + b
}
SapleComponent({ a: 1, b: 2 }) // 3
</script>
단순히 값으로 꺼내오는 것 뿐만 아니라 변수에 있는 값으로 꺼내오는 이른바 계산된 속성 이름 방식도 가능하다.
<script>
const key = 'a'
const obj = {
a: 1,
b: 1,
}
const { [key]: a } = obj
// a = 1
</script>
위 예제에서는 key는 a라는 값을 가지고 있는데, obj에서 이 a라는 값을 꺼내오기 위해 [key]문법을 사용했다.
이러한 계산된 속성 이름을 사용하려면 반드시 이름을 선언하는 :a 와 같은 변수 네이밍이 필요하다.
그렇지 않으면 에러가 발생한다.
계산된 이름인[key]로 값을 꺼내기만 했을 뿐, 어느 변수명으로 할당해야 할지 알 수 없기 때문에 에러가 발생한다고 한다.
배열 구조 분해 할당과 마찬가지로 전개 연산자...를 사용하면 나머지 값을 모두 가져올 수 있다.
<script>
const obj = {
a: 1,
b: 1,
c: 1,
d: 1,
e: 1,
}
const { a, b, ...rest } = obj
// rest { c: 1, d:1, e:1}
</script>
배열과 마찬가지로 이러한 전개 연산자는 순서가 중요하다.
<script>
const obj = {
a: 1,
b: 1,
c: 1,
d: 1,
e: 1,
}
const { a, b, ...rest } = obj
// rest { c: 1, d:1, e:1}
const { ...rest, a, b } = obj
// Uncaught SyntaxError : Rest element must be last element
</script>
➡️ 다음 글에서는 전개 구문에 대해 살펴보자.