구조 분해 할당과 스프레드 연산자
우리는 8장를 통해 let
, const
로 변수 선언 방식을 개선하고, 화살표 함수로 함수 작성을 더욱 간결하고 예측 가능하게 만들었습니다. 이러한 ES2015(ES6)의 변화는 자바스크립트 개발의 생산성과 코드 품질을 크게 향상시켰습니다. 이제 데이터 처리 방식을 혁신적으로 바꿔놓은 또 다른 강력한 기능들을 살펴볼 차례입니다.
구조 분해 할당(Destructuring Assignment) 과 스프레드 연산자(Spread Operator) 는 배열이나 객체에서 데이터를 추출하거나, 배열이나 객체를 복사/결합할 때 사용되는 문법입니다. 이 두 기능은 코드를 훨씬 간결하고 가독성 높게 만들어주며, 데이터를 다루는 다양한 상황에서 개발자의 편의성을 극대화합니다.
이번 장에서는 구조 분해 할당을 이용해 배열과 객체에서 값을 쉽게 추출하는 방법과, 스프레드 연산자를 이용해 배열과 객체를 유연하게 다루는 방법을 깊이 있게 탐구해 보겠습니다. 이 기능들을 마스터하는 것은 모던 자바스크립트 개발에서 데이터를 효율적으로 다루는 데 필수적입니다.
구조 분해 할당
구조 분해 할당 (Destructuring Assignment) 은 배열이나 객체의 속성(property)을 해체하여 그 값을 개별 변수에 할당할 수 있게 하는 자바스크립트 표현식입니다. 복잡한 데이터 구조에서 필요한 값만 깔끔하게 추출할 때 매우 유용합니다.
배열 구조 분해 (Array Destructuring)
배열의 각 요소를 해체하여 변수에 할당할 수 있습니다.
const colors = ["red", "green", "blue"];
// 배열 구조 분해 할당
const [firstColor, secondColor, thirdColor] = colors;
console.log(firstColor); // 결과: "red"
console.log(secondColor); // 결과: "green"
console.log(thirdColor); // 결과: "blue"
다양한 활용
-
일부 값만 추출: 필요한 요소만 선택적으로 가져올 수 있습니다. 건너뛰고 싶은 요소는 쉼표로 비워둡니다.
const numbers = [10, 20, 30, 40, 50]; const [a, , c, , e] = numbers; // 두 번째와 네 번째 요소 건너뛰기 console.log(a); // 결과: 10 console.log(c); // 결과: 30 console.log(e); // 결과: 50
-
기본값 설정: 할당할 값이
undefined
일 경우에 대비하여 기본값을 설정할 수 있습니다.const fruits = ["apple"]; const [myFruit, otherFruit = "orange"] = fruits; console.log(myFruit); // 결과: "apple" console.log(otherFruit); // 결과: "orange" (fruits 배열에 두 번째 요소가 없으므로 기본값 사용) const [item1, item2 = "default"] = []; console.log(item1); // 결과: undefined console.log(item2); // 결과: "default"
-
나머지 요소 가져오기 (
...rest
): 배열의 나머지 요소들을 새로운 배열로 묶을 수 있습니다. (스프레드 연산자와 동일한 문법이지만 여기서는 '나머지 파라미터' 역할)const scores = [80, 90, 70, 60, 95]; const [math, english, ...restScores] = scores; console.log(math); // 결과: 80 console.log(english); // 결과: 90 console.log(restScores); // 결과: [70, 60, 95] (새로운 배열)
-
변수 값 교환: 임시 변수 없이 두 변수의 값을 쉽게 교환할 수 있습니다.
let x = 1; let y = 2; [x, y] = [y, x]; // x와 y의 값을 교환 console.log(x); // 결과: 2 console.log(y); // 결과: 1
객체 구조 분해 (Object Destructuring)
객체의 프로퍼티를 해체하여 변수에 할당할 수 있습니다. 변수 이름은 객체의 프로퍼티 이름과 동일해야 합니다.
const person = {
name: "Alice",
age: 30,
city: "New York"
};
// 객체 구조 분해 할당
const { name, age } = person;
console.log(name); // 결과: "Alice"
console.log(age); // 결과: 30
// console.log(city); // ReferenceError: city is not defined (city는 할당하지 않음)
다양한 활용
-
다른 이름으로 할당: 객체의 프로퍼티 이름과 다른 이름으로 변수를 선언하고 싶을 때 사용합니다.
const { name: userName, age: userAge } = person; console.log(userName); // 결과: "Alice" console.log(userAge); // 결과: 30
-
기본값 설정: 할당할 프로퍼티가
undefined
일 경우에 대비하여 기본값을 설정할 수 있습니다.const { country = "Korea", age } = person; // person 객체에 country 프로퍼티가 없으므로 기본값 사용 console.log(country); // 결과: "Korea" console.log(age); // 결과: 30
-
나머지 프로퍼티 가져오기 (
...rest
): 객체의 나머지 프로퍼티들을 새로운 객체로 묶을 수 있습니다.const { name, ...restInfo } = person; console.log(name); // 결과: "Alice" console.log(restInfo); // 결과: { age: 30, city: "New York" } (새로운 객체)
-
중첩된 객체 구조 분해: 중첩된 객체에서 깊숙이 있는 프로퍼티를 한 번에 추출할 수 있습니다.
const userProfile = { id: 1, userInfo: { fullName: "Bob Johnson", email: "bob@example.com" }, preferences: { theme: "dark" } }; const { userInfo: { fullName, email }, // userInfo 객체를 분해하여 fullName, email 추출 preferences: { theme: userTheme } // preferences 객체를 분해하여 theme를 userTheme으로 추출 } = userProfile; console.log(fullName); // 결과: "Bob Johnson" console.log(email); // 결과: "bob@example.com" console.log(userTheme); // 결과: "dark"
-
함수 매개변수에서의 구조 분해: 함수의 매개변수에서 객체나 배열을 직접 구조 분해하여 사용할 수 있어 코드가 더욱 간결해집니다.
// 객체 매개변수 구조 분해 function displayUser({ name, age }) { console.log(`이름: ${name}, 나이: ${age}`); } const myUser = { name: "철수", age: 25 }; displayUser(myUser); // 결과: 이름: 철수, 나이: 25 // 배열 매개변수 구조 분해 function printCoordinates([x, y]) { console.log(`X: ${x}, Y: ${y}`); } const point = [10, 20]; printCoordinates(point); // 결과: X: 10, Y: 20
스프레드 연산자 ...
스프레드 연산자 (Spread Operator) (...
) 는 이터러블(iterable) 객체(배열, 문자열 등)나 객체의 내용을 개별 요소로 확장(펼치는)하는 데 사용됩니다. 배열, 객체, 함수의 인자 등 다양한 곳에서 활용됩니다.
배열에서의 스프레드 연산자
-
배열 결합 (Concatenation): 여러 배열을 쉽게 결합할 수 있습니다.
const arr1 = [1, 2]; const arr2 = [3, 4]; const combinedArr = [...arr1, ...arr2]; console.log(combinedArr); // 결과: [1, 2, 3, 4] const newArr = [0, ...arr1, 5, ...arr2]; console.log(newArr); // 결과: [0, 1, 2, 5, 3, 4]
-
배열 복사 (Shallow Copy): 원본 배열을 변경하지 않고 새로운 배열의 사본을 만들 수 있습니다. (얕은 복사임에 유의)
const original = [1, 2, 3]; const copy = [...original]; console.log(copy); // 결과: [1, 2, 3] console.log(original === copy); // 결과: false (다른 메모리 주소) copy.push(4); console.log(original); // 결과: [1, 2, 3] (원본 불변)
-
배열 요소 추가/삽입: 배열의 특정 위치에 요소를 쉽게 추가하거나 삽입할 수 있습니다.
const baseArray = [1, 2, 3]; const newArrayAtStart = [0, ...baseArray]; // 맨 앞에 추가 console.log(newArrayAtStart); // 결과: [0, 1, 2, 3] const newArrayAtMiddle = [1, ...baseArray.slice(1, 2), 99, ...baseArray.slice(2)]; // 중간에 삽입 (복잡) console.log(newArrayAtMiddle); // 결과: [1, 2, 99, 3] // 실용적으로는 splice나 map, filter를 조합하는 경우가 많음
-
이터러블을 배열로 변환: 유사 배열 객체나 다른 이터러블(예: Set, String)을 배열로 쉽게 변환할 수 있습니다.
const myString = "hello"; const charArray = [...myString]; console.log(charArray); // 결과: ["h", "e", "l", "l", "o"] const mySet = new Set([1, 2, 3]); const setToArray = [...mySet]; console.log(setToArray); // 결과: [1, 2, 3]
객체에서의 스프레드 연산자 (ES2018부터)
-
객체 병합 (Object Merging): 여러 객체를 병합하여 새로운 객체를 만들 수 있습니다.
const user = { name: "John", age: 30 }; const address = { city: "Seoul", zip: "12345" }; const details = { job: "Developer" }; const fullProfile = { ...user, ...address, ...details }; console.log(fullProfile); // 결과: { name: 'John', age: 30, city: 'Seoul', zip: '12345', job: 'Developer' }
이때 동일한 키가 있으면 뒤에 오는 객체의 값이 덮어씁니다.
const objA = { a: 1, b: 2 }; const objB = { b: 3, c: 4 }; const mergedObj = { ...objA, ...objB }; console.log(mergedObj); // 결과: { a: 1, b: 3, c: 4 } (b가 덮어써짐)
-
객체 복사 (Shallow Copy): 원본 객체를 변경하지 않고 새로운 객체의 사본을 만들 수 있습니다. (얕은 복사임에 유의)
const originalObj = { x: 1, y: 2 }; const copyObj = { ...originalObj }; console.log(copyObj); // 결과: { x: 1, y: 2 } console.log(originalObj === copyObj); // 결과: false copyObj.x = 10; console.log(originalObj.x); // 결과: 1 (원본 불변)
-
객체 프로퍼티 추가/업데이트: 기존 객체에 새로운 프로퍼티를 추가하거나, 특정 프로퍼티 값을 업데이트할 때 유용합니다.
const product = { id: 1, name: "Laptop", price: 1200 }; const updatedProduct = { ...product, price: 1100, category: "Electronics" }; console.log(updatedProduct); // 결과: { id: 1, name: 'Laptop', price: 1100, category: 'Electronics' }
함수 호출 시 스프레드 연산자 (...args
)
함수에 배열의 요소들을 개별적인 인자로 전달할 때 사용합니다. (이때는 '나머지 파라미터'와는 다름)
function sum(a, b, c) {
return a + b + c;
}
const numbersToSum = [1, 2, 3];
const result = sum(...numbersToSum); // 배열 요소를 개별 인자로 펼쳐서 전달
console.log(result); // 결과: 6
마무리하며
이번 장에서는 ES2015(ES6)에서 도입된 매우 강력하고 유용한 문법인 구조 분해 할당(Destructuring Assignment) 과 스프레드 연산자(Spread Operator) 에 대해 심도 있게 학습했습니다.
여러분은 배열과 객체에서 필요한 값만 간결하게 추출하는 구조 분해 할당의 다양한 활용법(일부 추출, 기본값, 나머지 요소, 변수 교환, 중첩 구조 분해, 함수 매개변수)을 익혔습니다. 또한, 배열이나 객체의 내용을 개별 요소로 펼쳐서 사용하는 스프레드 연산자가 배열 결합, 복사, 요소 추가/삽입, 객체 병합, 복사, 프로퍼티 추가/업데이트, 그리고 함수 인자 전달 등 광범위한 상황에서 코드의 간결성과 가독성을 얼마나 높여주는지 확인했습니다.
이 두 기능은 모던 자바스크립트 개발에서 데이터를 다루는 방식을 근본적으로 변화시켰습니다. 여러분의 코드를 더욱 깔끔하고 효율적으로 만들며, 불필요한 임시 변수 사용을 줄여줄 것입니다. 다양한 예제들을 직접 타이핑하고 응용해보면서 이 기능들을 여러분의 것으로 만들고, 실제 프로젝트에서 적극적으로 활용하는 연습을 하시길 바랍니다.\