WeniVooks

검색

JavaScript 에센셜

전개 구문과 구조 분해 할당

이번에는 배열이나 객체를 다룰 때 유용한 전개 구문과 구조 분해 할당에 대해 알아보겠습니다. 전개 구문은 데이터 구조를 확장하거나 복사할 때 사용하며, 구조 분해 할당은 데이터를 쉽게 분해하여 변수에 할당할 수 있게 해줍니다.

1. 전개 구문

전개 구문은 배열이나 객체와 같은 데이터 구조를 확장할 때 사용하는 문법입니다. 이를 통해 배열이나 객체를 쉽게 복사하거나, 새로운 배열이나 객체를 생성할 수 있습니다. 전개 식(Spread syntax) 이라고 표현하기도 합니다.

‘퍼지다, 펼치다’ 라는 의미의 spread처럼, 배열이나 객체로 포장되어 있는 데이터를 가지런히 펼쳐놓는 이미지를 생각하시면 되겠습니다.

1.1. 배열의 전개 구문

배열의 전개 구문은 대괄호([ ]) 안에서 세 개의 점(...)을 사용하여 배열을 확장합니다.

1.1.1. 배열 합치기

다음처럼 전개 구문을 이용하여 두 개의 배열을 합칠 수 있습니다.

const fruits = ['사과', '파인애플', '수박']; const vegetables = ['당근', '오이', '양파']; const food = [...fruits, ...vegetables]; console.log(food);

위 코드에서는 fruitsvegetables이라는 두 개의 배열을 전개 구문을 사용하여 펼친(spread) 후 합치면 새로운 배열 food를 생성할 수 있습니다.

1.1.2. 배열 복사하기

기존 배열을 복사하여 새로운 배열을 만들 수 있습니다.

const fruits = ['사과', '파인애플', '수박', '딸기']; const fruits2 = [...fruits]; fruits2.push('키위'); console.log(fruits); console.log(fruits2);

전개 구문을 이용하여 fruits 배열을 복사해 fruits2 배열을 만들고, push 메서드로 새로운 요소를 추가합니다. 이때 fruits 배열은 변하지 않고 fruits2 배열만 변경됩니다. 이를 통해 전개 구문을 이용하여 배열을 얕은 복사하여 새로운 배열을 생성하므로 기존 배열과는 별개의 배열이 됩니다.

1.2. 객체의 전개 구문

객체의 전개 구문은 배열과 마찬가지로 중괄호({ }) 안에서 세 개의 점(...)을 사용하여 객체를 확장합니다.

1.2.1. 객체 합치기

다음처럼 전개 구문을 이용하여 두 개의 객체를 합칠 수 있습니다.

const weniv1 = { gary: 1, binky: 2 }; const weniv2 = { licat: 3 }; const weniv3 = { ...weniv1, ...weniv2 }; console.log(weniv3);

위 코드는 weniv1weniv2라는 두 개의 객체를 전개 구문을 사용하여 합친 weniv3 객체를 생성합니다.

만약 두 객체에 같은 이름의 key가 있다면, key의 값은 나중에 온 객체의 키값으로 업데이트됩니다.

const weniv1 = { gary: 1, binky: 2 }; const weniv2 = { binky: 3 }; const weniv3 = { ...weniv1, ...weniv2 }; console.log(weniv3);
1.2.2. 객체 복사하기

기존 객체를 복사하여 새로운 객체를 만들 수 있습니다.

const user1 = { name: 'licat', address: 'jeju' }; const user2 = { ...user1 }; user2.company = 'weniv'; console.log(user1); console.log(user2);

배열의 전개 구문처럼 객체 전개 구문 역시 기존 객체를 복사해 독립적인 새로운 객체를 만들 수 있습니다.

2. 구조 분해 할당

많은 분들이 헷갈리는 악명 높은 구조 분해 할당(Destructuring)입니다. 한 번에 이해되지 않으니 여러 번 반복하고 다양한 예제로 실습해보시길 권장합니다. 구조 분해 할당은 ES6 부터 지원하는 문법으로, 배열이나 객체와 같은 데이터 구조를 분해하여 변수에 할당하는 표현식입니다. 이를 통해 변수에 속성이나 요소를 간편하게 할당할 수 있습니다.

쉽게 말하자면, 배열이나 객체를 분해하여 안에 있는 데이터를 변수에 순서대로 할당해주는 문법입니다.

'Destructuring' 이라는 이름에 대하여 생각해봅시다.
destructure는 '-의 구조를 파괴하다'라는 뜻을 가지고 있습니다.

"de-"는 "제거하다"라는 뜻의 접두사이고, "structure"는 "구조"를 뜻합니다. 즉, "destructuring"은 "구조를 해체하는 행위"를 뜻합니다.

이렇듯 영어 구조적 특징을 통해 자바스크립트 문법을 해석해보는것도 학습에 도움이 됩니다

ES6 이전에 사용했던 수동적인 구조 분해 할당에 대해 살펴봅시다.

let food1, food2, food3; const categories = { food1: '과일', food2: '채소', food3: '육류' }; food1 = categories.food1; food2 = categories.food2; food3 = categories.food3; console.log(food1); console.log(food2); console.log(food3);

위의 코드에서 우리는 객체 안의 값을 하나 하나 빼내어 각각 별개의 변수에 할당하는 모습을 볼 수 있습니다. 할당하고자 하는 값에 해당하는 변수 선언이 필요하기 때문에, n개의 할당을 해주고자 하면 n줄의 코드 작성이 필요합니다.

위의 코드는 지금도 사용함에 있어서 문법적인 오류가 없는 코드입니다. 하지만 더 간결하고 빠르게 작성할 수 있는 구문으로 개선해봅시다.

2.1. 구조 분해 할당의 기본 구조

할당연산자(=)를 기준으로 왼쪽에 있는 중괄호는 구조 분해 할당을 의미합니다. 오른쪽에 있는 중괄호는 객체를 나타냅니다. 중괄호 안에 있는 key와 객체의 값을 할당하고자 하는 변수 이름을 콜론(:)으로 연결합니다. 변수1에는 key1의 값이 할당되고, 변수2에는 key2의 값이 할당됩니다. 즉 변수1에는 값1, 변수2에는 값2가 할당됩니다.

const { key1 : 변수1, key2 : 변수2 } = { key1 : '값1', key2 : '값2' }; console.log(변수1); console.log(변수2);

변수명과 key가 동일하다면, 아래와 같이 간단하게 작성할 수 있습니다.

const { key1, key2 } = { key1: '값1', key2: '값2' }; console.log(key1); console.log(key2);

이제 구조 분해 할당을 통해 처음에 했던 수동 구조 분해 할당을 처리해보겠습니다.

const { food1, food2, food3 } = { food1: '과일', food2: '채소', food3: '육류' }; console.log(food1); console.log(food2); console.log(food3);

앞서 작성했던 5줄의 코드와 달리, 1줄의 코드로 변수에 값을 할당할 수 있습니다.

만약 객체를 반환하는 함수가 있을 경우, 함수의 반환값을 받는 변수를 굳이 만들 필요도 없습니다.

const obj = { food1: '과일', food2: '채소', food3: '육류' }; function objReturn() { return obj; } // 반환값을 바로 구조 분해 할당합니다. const { food1, food2, food3 } = objReturn(); console.log(food1); console.log(food2); console.log(food3);

이렇듯 구조 분해 할당을 이용하면 반복과 불필요한 변수 생성을 줄여 코드를 깔끔하게 작성할 수 있도록 도와줍니다.

2.2. 배열의 구조 분해 할당

지금까지 객체의 구조 분해 할당을 주로 살펴봤습니다. 배열의 구조 분해 할당은 대괄호( [ ] )를 사용하여 할당할 변수 이름을 나열하는 방식입니다. 이를 통해 배열의 요소를 각각의 변수에 할당할 수 있습니다. 아래는 배열의 구조 분해 할당을 사용한 예시입니다. 배열의 요소를 순서대로 변수에 할당할 수 있습니다.

const arr = [1, 2, 3]; const [a, b, c] = arr; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3

배열의 요소를 비어두면 필요한 요소만 추출할 수 있습니다.

const [a, , c] = [1, 2, 3, 4, 5]; console.log(a); console.log(c);
2.3 함수의 구조 분해 할당

함수의 매개변수를 객체나 배열로 받을 때 구조 분해 할당을 사용할 수 있습니다. 구조 분해 할당을 사용하여 전달인자를 매개변수에 구조 분해 할당하여 사용할 수 있습니다.

function func1({ a, b }) { console.log(a); console.log(b); } const obj = { a: 10, b: 20 }; func1(obj); func1({a: 30}); function func2([a, b]) { console.log(a); console.log(b); } const arr = [1, 2]; func2(arr);

위 코드의 매개변수는 전달받은 인자값을 구조 분해 할당하여 사용합니다. 객체를 매개변수로 사용하면 순서와 상관없이 key 값으로 할당됩니다. 다만 배열을 매개변수로 사용할 때는 순서에 유의해야 합니다. 객체의 key 값이 없으면 undefined가 할당되며, 배열의 요소가 부족하면 undefined가 할당됩니다.

// func1
{a, b} = {a: 10, b:20}
 
// func2
[a, b] = [1, 2];
// func1
{a, b} = {a: 10, b:20}
 
// func2
[a, b] = [1, 2];
2.3.1. 기본값 설정
function func1({ a, b }) { console.log(a); console.log(b); } func1(); // TypeError

함수의 매개변수에서 구조 분해 할당을 사용할 때 인자가 전달되지 않으면 오류가 발생할 수 있습니다. 함수에 인자를 전달하지 않으면 기본적으로 undefined가 전달됩니다. 구조 분해 할당은 undefined이나 null에 대해 동작하지 않기 때문에 오류가 발생합니다. 인자가 전달되지 않았을 때 발생하는 오류를 방지하기 위해 매개변수의 기본값을 설정할 수 있습니다.

function userInfo({name, age}={}) { console.log(`이름: ${name}, 나이: ${age}`); } userInfo({name: 'licat', age: 20}); userInfo({name: 'binky'}); userInfo();

인자가 전달되지 않더라도 기본값이 빈 배열({})로 설정되어 오류가 발생하지 않고, nameage에는 undefined가 할당됩니다.

name과 age 속성에도 기본값을 설정할 수 있습니다. 객체에 전달되는 속성이 없거나 undefined일 때 기본값이 할당됩니다.

function userInfo({name='익명', age=0}={}) { console.log(`이름: ${name}, 나이: ${age}`); } userInfo({name: 'binky'}); userInfo();

undefined는 배열로도 구조 분해 할당을 할 수 없기 때문에 배열을 함수의 매개변수로 사용할 때 기본값이 설정되어 있지 않으면 오류가 발생할 수 있습니다. 이를 방지하기 위해서 빈 배열을 기본값으로 설정합니다.

function sum([a,b]=[]){ console.log(a + b); } sum([1,2]);

각 매개변수의 기본값도 설정할 수 있습니다.

function sum([a=0, b=0]=[]){ console.log(a + b); } sum([1,2]); sum();
6.2 반복문7장 함수