4.Node.js/JavaScript&TypeScript

[JavaScript] 2편. 객체와 배열 다루기 : 구조 분해, Spread/Rest

쿼드큐브 2025. 12. 5. 08:24
반응형
반응형

 

[JavaScript] 2편. 객체와 배열 다루기 : 구조분해, Spread/Rest

 

📚 목차
1. 객체 리터럴 & 프로퍼티 (Object Literal & Property)
2. 배열 기본 조작 (Basic Array Manipulation)
3. 구조 분해 할당(Destructuring Assignment)
4. Spread (...) / Rest (...)
✔ 마무리

 

JavaScript에서 가장 많이 사용하는 자료 구조는 객체(Object)와 배열(Array)입니다.
Node.js 개발에서 API 응답 처리, 설정 파일(JSON), DB 결과 매핑, 캐시 데이터 등 거의 모든 곳에서 필수적으로 다루게 됩니다.

객체와 배열 다루기 삽화 이미지
객체와 배열 다루기 삽화 이미지

 

 

📂 [GitHub 실습 코드 보러가기] (https://github.com/cericube/nodejs-tutorials/JavaScript)

 

1. 객체 리터럴 & 프로퍼티 (Object Literal & Property)

JavaScript에서 객체(Object)는 언어의 핵심이자 가장 중요한 데이터 구조입니다.

Node.js에서 JSON을 읽고 쓰는 것, API 응답 값을 파싱하는 것, 설정 파일을 관리하는 것,

심지어 Express나 Fastify 같은 서버 프레임워크에서 요청/응답을 다루는 것도 모두 “객체”를 기반으로 합니다.


자바스크립트 객체를 이해하면 Node.js 프로그래밍의 절반을 이해했다고 해도 과언이 아닙니다.

 

🔷 객체 리터럴(Object Literal)

객체는 이름(키)과 값(밸류)의 쌍으로 이루어진 데이터 컬렉션입니다. 실세계의 사물처럼 여러 속성을 하나의 단위로 묶을 때 사용됩니다.

 

가장 일반적인 객체 생성 방법은 객체 리터럴(Object Literal)을 사용하는 것입니다.

중괄호 { } 안에 키(key)와 값(value)을 콜론(:)으로 연결하고, 각 쌍은 쉼표(,)로 구분합니다.

// 객체 리터럴을 사용하여 'person' 객체 정의
const person = {
  name: 'Alice',     // 문자열 값
  age: 30,           // 숫자 값
  isStudent: false,  // 불리언 값
  hobbies: ['coding', 'reading'], // 배열 값
  greet: function() { // 함수 (메서드)
    console.log(`Hello, my name is ${this.name}`);
  }
};

console.log(person);
// 출력: {name: 'Alice', age: 30, isStudent: false, hobbies: ['coding', 'reading'], greet: f}

 

🔷 프로퍼티 접근 및 조작

객체 내의 값, 즉 프로퍼티(Property)에 접근하는 방법은 두 가지가 있습니다.

 

✔️ 점 표기법 (Dot Notation)

가장 흔하게 사용되며, 키 이름이 유효한 식별자인 경우에 사용합니다.

// 기본 객체 정의
const user = {
  name: 'Alice',
  age: 30,
  isAdmin: false
};

console.log("--- 초기 객체 상태 ---");
// 출력: { name: 'Alice', age: 30, isAdmin: false }
console.log(user); 

// ▶ 1. 프로퍼티 추가 (Addition)
// 객체에 존재하지 않는 'email' 키에 값을 할당하면 새로운 프로퍼티가 추가됩니다.
user.email = "alice@example.com";
console.log("\n--- 'email' 추가 후 ---");
// 출력: alice@example.com
console.log(user.email);   
// 출력: { name: 'Alice', age: 30, isAdmin: false, email: 'alice@example.com' }
console.log(user);

// ▶ 2. 프로퍼티 수정 (Modification)
// 이미 존재하는 'age' 키에 새로운 값을 할당하면 기존 값이 수정됩니다.
user.age = 31;
console.log("\n--- 'age' 수정 후 ---");
// 출력: 31
console.log(user.age);
// 출력: { name: 'Alice', age: 31, isAdmin: false, email: 'alice@example.com' }
console.log(user);

// ▶ 3. 프로퍼티 삭제 (Deletion)
// delete 연산자를 사용하여 'isAdmin' 프로퍼티 자체를 객체에서 제거합니다.
delete user.isAdmin;
console.log("\n--- 'isAdmin' 삭제 후 ---");
// 출력: undefined (프로퍼티가 존재하지 않음)
console.log(user.isAdmin);
// 출력: { name: 'Alice', age: 31, email: 'alice@example.com' }
console.log(user);

 

✔️ 대괄호 표기법 (Bracket Notation)

키 이름에 공백, 하이픈 등 특수문자가 포함되거나, 키 이름을 변수로 동적으로 결정해야 할 때 사용합니다. 키 이름은 문자열로 감싸야합니다.

// 기본 객체 정의 (이번에는 키에 공백이 포함된 경우를 가정)
const user = {
  'full name': 'Alice Smith', // 공백 때문에 대괄호 표기법이 필수적임
  age: 30,
  isAdmin: false
};

console.log("--- 초기 객체 상태 ---");
// 출력: { 'full name': 'Alice Smith', age: 30, isAdmin: false }
console.log(user);

// ▶ 1. 프로퍼티 추가 (Addition)
// 키를 변수에 저장하여 동적으로 접근하거나, 문자열 리터럴로 직접 접근합니다.
const emailKey = "email";
user[emailKey] = "alice@example.com";
user["city of residence"] = "Seoul"; 

console.log("\n--- 'email' 및 'city of residence' 추가 후 ---");
// 출력: alice@example.com
console.log(user[emailKey]);
// 출력: Seoul
console.log(user["city of residence"]);
// 출력: { 'full name': 'Alice Smith', age: 30, isAdmin: false, email: 'alice@example.com', 'city of residence': 'Seoul' }
console.log(user);

// ▶ 2. 프로퍼티 수정 (Modification)
// 이미 존재하는 'age' 키에 새로운 값을 할당하여 수정합니다.
const ageKey = 'age';
user[ageKey] = 31;
console.log("\n--- 'age' 수정 후 ---");
// 출력: 31
console.log(user[ageKey]); 
// 출력: { 'full name': 'Alice Smith', age: 31, isAdmin: false, email: 'alice@example.com', 'city of residence': 'Seoul' }
console.log(user);

// ▶ 3. 프로퍼티 삭제 (Deletion)
// delete 연산자와 대괄호 표기법을 함께 사용하여 'isAdmin' 프로퍼티를 제거합니다.
const adminKey = 'isAdmin';
delete user[adminKey];
console.log("\n--- 'isAdmin' 삭제 후 ---");
// 출력: undefined (프로퍼티가 존재하지 않음)
console.log(user[adminKey]);
// 출력: { 'full name': 'Alice Smith', age: 31, email: 'alice@example.com', 'city of residence': 'Seoul' }
console.log(user);

 

✔️ 프로퍼티 축약 (Property Shorthand) - ES2015

객체를 생성할 때, 할당하려는 변수명과 객체의 키 이름이 같을 경우, 중복을 제거하고 짧게 작성할 수 있는 문법입니다.

const name = "Bob";
const age = 30;

// 일반적인 작성
// const person = { name: name, age: age }; 

// 프로퍼티 축약(Shorthand) 적용
const person = { name, age }; 

console.log(person); // { name: "Bob", age: 30 }

📌 Node.js 환경에서는 매우 흔하게 사용되는 최신 기본 문법입니다.

Express의 JSON 응답, Config 파일 작성, 데이터베이스 쿼리 객체 리턴 등 변수와 객체 키의 이름이 일치하는 경우에 간결함을 위해 필수로 사용됩니다.

 

✔️ Object.hasOwn() - ES2022

객체가 특정 프로퍼티를 직접 소유하고 있는지 확인하는 안전하고 권장되는 방법입니다.

 

기존에는 obj.hasOwnProperty() 메서드를 사용했지만, 다음과 같은 문제점이 있었습니다.

▸ 객체가 hasOwnProperty라는 이름의 프로퍼티를 오버라이드하면 오동작할 수 있습니다.
▸ 프로토타입 체인에 의한 문제를 회피하기 위해 복잡하게 Object.prototype.hasOwnProperty.call(obj, prop)처럼 사용해야 했습니다.

 

이러한 문제점을 해결하기 위해 ES2022 정식 표준에서는 정적 메서드인 Object.hasOwn()이 추가되었습니다.

const user = { name: "Alice" };

console.log(Object.hasOwn(user, "name")); // true (직접 소유)
console.log(Object.hasOwn(user, "age"));  // false (소유하지 않음)

 

✔️ 객체를 JSON으로 바꿔서 보기

복잡한 객체를 콘솔에서 디버깅하거나 로그로 남길 때, 가독성 높게 출력하기 위해 JSON.stringify()를 활용합니다.

const user = { 
  id: 1, 
  name: "Charlie", 
  details: { city: "London", registered: true }
};

// JSON.stringify(value, replacer, space)
console.log(JSON.stringify(user, null, 2));

 

 

2. 배열 기본 조작 (Basic Array Manipulation)

배열(Array)은 순서(인덱스)를 가진 값(요소)의 리스트입니다. JavaScript의 배열은 C나 Java와 달리 크기가 고정되어 있지 않은 동적 배열(dynamic array)이며, 한 배열 안에 숫자, 문자열, 불리언, 객체 등 다양한 타입의 요소가 섞여 들어갈 수 있다는 강력한 특징이 있습니다.

// JavaScript 배열의 유연성
const dynamicArray = [1, "A", true, { x: 10 }, null];

 

🔷 배열 정의 및 접근

// 배열 리터럴을 사용하여 'fruits' 배열 정의
const fruits = ['Apple', 'Banana', 'Cherry', 'Durian'];

// 인덱스를 사용하여 요소에 접근 (0부터 시작)
console.log(fruits[0]); // 출력: Apple
console.log(fruits[3]); // 출력: Durian

// 배열의 길이 확인
console.log(fruits.length); // 출력: 4

 

🔷 배열의 주요 조작 메서드

배열의 끝이나 앞에서 요소를 추가하거나 제거하는 기본 메서드는 데이터를 스택(Stack) 또는 큐(Queue)처럼 다룰 때 유용하며, 원본 배열을 직접 변경(mutate)합니다.

  위치 설명
push() 배열의 끝에 요소를 추가하고 새 길이 반환
pop() 배열의 끝 요소를 제거하고, 제거된 요소 반환
unshift() 배열의 앞에 요소를 추가하고 새 길이 반환
shift() 배열의 앞 요소를 제거하고, 제거된 요소 반환
// push / pop 실습 (Stack 구조)
const numbers = [1, 2, 3];
numbers.push(4);      // [1, 2, 3, 4]
console.log(`Push 후: ${numbers}`);

numbers.pop();        // 4가 제거됨
console.log(`Pop 후: ${numbers}`); // [1, 2, 3]

// unshift / shift 실습 (Queue 구조)
const q = [2, 3];
q.unshift(1);         // [1, 2, 3]
console.log(`Unshift 후: ${q}`);

q.shift();            // 1이 제거됨
console.log(`Shift 후: ${2, 3}`); // [2, 3]

 

🔷 요소 검색 메서드 (Element Search Methods)

배열 내에서 특정 값의 존재 여부를 확인하거나, 특정 조건을 만족하는 요소를 찾는 것은 배열 조작에서 가장 기본적이고 중요한 작업입니다. JavaScript는 이 작업을 위한 여러 메서드를 제공합니다.

 

1. 단순 값/인덱스 기반 검색

특정 값이 배열에 포함되어 있는지, 혹은 해당 값이 어느 인덱스에 위치하는지를 확인할 때 사용합니다.

메서드 설명 반환값
indexOf() 특정 요소가 배열에서 처음 발견되는 인덱스를 반환합니다. 인덱스 (없으면 −1)
includes() 특정 요소의 **포함 여부(true/false)**를 확인합니다. true 또는 false

 

2. 조건(콜백 함수) 기반 검색: find 계열

배열 요소를 하나씩 순회하면서, 콜백 함수가 정의한 조건을 만족하는 요소를 찾고 싶을 때 사용하는 메서드들이 있습니다.


기존의 find()와 findIndex()는 항상 배열의 앞(인덱스 0)부터 검색을 시작합니다.
반면, ES2023에서 추가된 findLast()와 findLastIndex()는 배열의 뒤(마지막 인덱스)부터 검색을 시작하는 방식으로 동작합니다.


두 방식은 동일한 조건을 사용하지만 탐색 방향이 다르기 때문에, 특히 배열 끝에 가까운 데이터를 찾을 때 findLast() 계열 메서드가 검색 효율을 높여주는 장점이 있습니다.

메서드 설명 반환
find() 조건을 만족하는 첫 번째 요소를 반환합니다. 요소 값 (없으면 undefined)
findIndex() 조건을 만족하는 첫 번째 요소의 인덱스를 반환합니다. 인덱스 (없으면 -1)
findLast() 조건을 만족하는 첫 번째(= 배열의 마지막 기준) 요소를 반환합니다. 요소 값 (없으면 undefined)
findLastIndex() 조건을 만족하는 첫 번째 요소의 인덱스를 반환합니다. 인덱스 (없으면 -1)
const fruits = ["apple", "banana", "melon", "orange", "banana"];
const nums = [1, 3, 5, 7, 8, 10];

console.log("--- 1. 단순 값/인덱스 검색 ---");

// indexOf(): 'banana'가 처음 나타나는 인덱스는 1
console.log(`'banana'의 첫 인덱스: ${fruits.indexOf("banana")}`); // 출력: 1

// includes(): 'grape'가 배열에 포함되어 있는가?
console.log(`'grape' 포함 여부: ${fruits.includes("grape")}`); // 출력: false


console.log("\n--- 2. 조건 기반 검색 (앞에서부터) ---");

// find(): 5보다 큰 첫 번째 요소를 찾습니다.
console.log(`앞에서 찾은 5보다 큰 수: ${nums.find(n => n > 5)}`); // 출력: 7

// findIndex(): 짝수인 첫 번째 요소의 인덱스를 찾습니다.
console.log(`앞에서 찾은 짝수의 인덱스: ${nums.findIndex(n => n % 2 === 0)}`); // 출력: 4 (nums[4]는 8)


console.log("\n--- 3. ES2023 조건 기반 검색 (뒤에서부터) ---");

// findLast(): 뒤에서부터 검색하여 처음으로 짝수인 요소(10)를 찾습니다.
console.log(`뒤에서 찾은 짝수: ${nums.findLast(n => n % 2 === 0)}`);     // 출력: 10

// findLastIndex(): 뒤에서부터 검색하여 처음으로 5보다 큰 요소(10)의 인덱스를 찾습니다.
console.log(`뒤에서 찾은 5보다 큰 수의 인덱스: ${nums.findLastIndex(n => n > 5)}`); // 출력: 5 (nums[5]는 10)

// fruits 배열에서 'banana'가 가장 마지막에 나타나는 인덱스를 찾습니다.
console.log(`'banana'의 마지막 인덱스: ${fruits.findLastIndex(f => f === "banana")}`); // 출력: 4

 

🔷 slice vs splice — 복사와 변경의 차이

slice와 splice는 이름은 비슷하지만 기능은 완전히 다릅니다. 이 둘의 차이를 명확히 이해하는 것은 매우 중요합니다.

 

1. slice - (원본 유지, 복사) : 새로운 배열 생성

slice(startIndex, endIndex)는 원본 배열을 그대로 두고 새로운 배열을 만들어 반환합니다.

 

slice() 메서드로 배열을 복사한 후, 그 복사본인 copyArray에 값을 추가하거나 삭제하는 것은 원본 배열에는 아무런 영향을 미치지 않습니다.


이는 slice()가 얕은 복사(Shallow Copy)를 통해 완전히 새로운 배열을 생성하기 때문입니다.

const originalArray = ['A', 'B', 'C', 'D', 'E'];

// 1. 부분 복사: 인덱스 1('B')부터 4 이전('D')까지
const subArray = originalArray.slice(1, 4);
console.log(`subArray: ${subArray}`);       // 출력: B,C,D
console.log(`원본 유지 확인: ${originalArray}`); // 출력: A,B,C,D,E

// 2. 끝까지 복사: 인덱스 2('C')부터 끝까지
const tailArray = originalArray.slice(2);
console.log(`tailArray: ${tailArray}`);     // 출력: C,D,E

// 3. 전체 복사 (Shallow Copy): 
const copyArray = originalArray.slice();
copyArray.push('F'); // 복사본에 추가해도 원본에 영향 없음

console.log(`copyArray: ${copyArray}`);     // 출력: A,B,C,D,E,F
console.log(`원본 유지 확인: ${originalArray}`); // 출력: A,B,C,D,E

// 4. 음수 인덱스: 끝에서 3번째('C')부터 끝까지
const negativeSlice = originalArray.slice(-3);
console.log(`negativeSlice: ${negativeSlice}`); // 출력: C,D,E

 

2. splice - (원본 변경, 삽입/삭제)

splice(startIndex, deleteCount, ...items) 메서드는 원본 배열을 직접 변경하며(mutating), 요소를 제거, 교체, 추가하는 만능 도구입니다.
▸ 제거: deleteCount만큼 요소를 삭제합니다.
▸ 교체/추가: 세 번째 인자부터는 삭제된 자리에 삽입될 요소를 지정합니다.

let mutableArray = [10, 20, 30, 40, 50];

console.log(`\n--- Splice 실습 (원본 변경) ---`);

// 1. 삭제: 인덱스 1(20)부터 2개 요소 삭제
const deleted1 = mutableArray.splice(1, 2); 
console.log(`삭제된 요소: ${deleted1}`);   // 출력: 20,30
console.log(`남은 배열: ${mutableArray}`); // 출력: 10,40,50 (원본 변경됨)

// 2. 교체: 인덱스 1(40)에서 1개 삭제 후 'A', 'B' 삽입
const deleted2 = mutableArray.splice(1, 1, 'A', 'B'); 
console.log(`삭제된 요소: ${deleted2}`);   // 출력: 40
console.log(`남은 배열: ${mutableArray}`); // 출력: 10,A,B,50 (원본 변경됨)

// 3. 추가: 인덱스 2('B') 위치에 'New' 요소 삽입 (삭제 개수: 0)
mutableArray.splice(2, 0, 'New'); 
console.log(`삽입 후 배열: ${mutableArray}`); // 출력: 10,A,New,B,50 (원본 변경됨)
반응형

 

3. 구조 분해 할당 (Destructuring Assignment)

구조 분해 할당(Destructuring Assignment)은 배열이나 객체의 프로퍼티를 개별 변수로 쉽고 간결하게 추출할 수 있게 해주는 JavaScript의 강력한 문법입니다. 마치 포장된 선물 상자(객체 또는 배열)에서 원하는 내용물만 쏙 꺼내는 것과 같습니다.

 

🔷 1. 객체 구조 분해 할당 (Object Destructuring)

객체에서 필요한 프로퍼티의 키 이름을 사용하여 해당 값을 추출하고, 같은 이름의 변수에 할당합니다. 중괄호 {}를 사용합니다.

▸ 순서 무관 : 객체는 순서가 없으므로, 변수 선언 순서는 중요하지 않습니다. 키 이름만 일치하면 됩니다.
▸ 일치하는 이름 : 추출할 변수 이름은 객체의 프로퍼티 키와 정확히 일치해야 합니다.

const product = {
  name: 'Laptop Pro',
  price: 1500,
  category: 'Electronics',
  inStock: true
};

// 순서를 바꿔서 추출해도 정상 작동합니다.
const { price, name, inStock } = product; 

console.log(`제품명: ${name}`);      // 출력: Laptop Pro
console.log(`가격: ${price}`);        // 출력: 1500
console.log(`재고 여부: ${inStock}`); // 출력: true

 

1. 새 변수 이름 사용 (Alias):

변수 이름이 이미 사용 중이거나, 키 이름보다 더 명확한 이름으로 변경하고 싶을 때 콜론(:)을 사용하여 별칭을 지정합니다.

const item = {
  name: 'Coffee Maker',
  price: 50,
  sku: 'CM-1001' // Stock Keeping Unit (재고 관리 번호)
};

// 키 'sku'를 추출하여 'productCode'라는 새 변수에 할당합니다.
const { name, sku: productCode } = item;

console.log(`상품명: ${name}`);         // 출력: Coffee Maker
console.log(`상품 코드: ${productCode}`); // 출력: CM-1001
// console.log(sku); // ❌ 에러 발생: sku 변수는 정의되지 않았습니다.

 

2. 기본값 설정 (Default Values)

객체에 해당 키가 존재하지 않아 undefined가 할당되는 것을 방지하기 위해 **등호($=$)**를 사용하여 기본값을 지정할 수 있습니다.

const settings = {
  theme: 'dark',
  fontSize: 14 // lineSpacing 키는 없음
};

// theme과 fontSize는 객체에 있으므로 객체 값이 할당됩니다.
// lineSpacing은 객체에 없으므로 기본값 1.5가 할당됩니다.
const { theme, lineSpacing = 1.5, fontSize } = settings;

console.log(`테마: ${theme}`);            // 출력: dark
console.log(`줄 간격 (기본값): ${lineSpacing}`); // 출력: 1.5

 

3. 기본값과 별칭 동시 사용

기본값 설정과 별칭 지정을 함께 사용할 때는 별칭(:) 뒤에 기본값(=)을 지정합니다.

const profile = { firstName: 'Jane', lastName: 'Doe' };

// company 키가 없으므로 'Unknown'을 기본값으로 사용하고, 변수명은 'orgName'으로 지정
const { company: orgName = 'Unknown', lastName } = profile;

console.log(`회사 이름: ${orgName}`);  // 출력: Unknown

 

4. 중첩 객체 분해 (Nested Destructuring)

객체 내부에 또 다른 객체가 포함되어 있을 때, 한 번의 할당으로 깊숙한 프로퍼티까지 분해할 수 있습니다.

const application = {
  version: '1.0',
  metadata: {
    author: 'Codemaster',
    date: '2024-01-01'
  }
};

// metadata 객체를 분해한 후, 그 안의 author와 date를 추출합니다.
const { metadata: { author, date } } = application;

console.log(`개발자: ${author}`); // 출력: Codemaster
console.log(`작성일: ${date}`);   // 출력: 2024-01-01

 


🔷 2. 배열 구조 분해 할당 (Array Destructuring)

배열 구조 분해 할당은 배열의 요소를 위치(인덱스)에 따라 개별 변수로 추출하는 문법입니다.

대괄호 []를 사용하여 선언합니다.

객체와 달리 배열은 순서가 핵심이므로, 변수의 선언 순서가 할당되는 요소의 위치를 결정합니다.

▸ 순서 중요 : 변수 선언 순서대로 배열의 요소가 매칭됩니다.

▸ 건너뛰기 : 불필요한 요소는 쉼표(,)만 사용하여 건너뛸 수 있습니다.

▸ 변수명 자유변수 이름은 키 이름과 무관하게 자유롭게 지정할 수 있습니다.

 

1. 기본 구조 분해 및 건너뛰기

배열 요소를 순서대로 추출하며, 필요 없는 요소는 쉼표를 사용하여 해당 인덱스를 생략합니다.

const userProfile = ['Sam', 35, 'New York', 'Developer'];

// 첫 번째, 세 번째, 네 번째 요소를 추출하고, 두 번째 요소(35)는 건너뛰었습니다.
const [name, , city, occupation] = userProfile; 

console.log(`이름: ${name}`);         // 출력: Sam
console.log(`거주지: ${city}`);        // 출력: New York
console.log(`직업: ${occupation}`);   // 출력: Developer

 

2. 변수 값 교환 (Swapping Variables)

임시 변수 없이 단 한 줄의 구조 분해 문법만으로 두 변수의 값을 효율적으로 교환할 수 있습니다

let tempA = 'Hello';
let tempB = 'World';

console.log(`교환 전: A=${tempA}, B=${tempB}`); // 출력: 교환 전: A=Hello, B=World

// 오른쪽 배열 [tempB, tempA]가 분해되어 왼쪽 변수에 순서대로 할당됩니다.
[tempA, tempB] = [tempB, tempA]; 

console.log(`교환 후: A=${tempA}, B=${tempB}`); // 출력: 교환 후: A=World, B=Hello

 

3. 기본값 설정 (Default Values)

배열에 요소가 충분하지 않아 undefined가 할당될 경우를 대비하여 기본값을 설정할 수 있습니다.

const ranking = ['Gold', 'Silver'];

// Bronze 요소는 배열에 없으므로 기본값 'Bronze'가 할당됩니다.
const [first, second, third = 'Bronze', fourth = 'None'] = ranking;

console.log(`1등: ${first}`);    // 출력: Gold
console.log(`3등: ${third}`);     // 출력: Bronze
console.log(`4등: ${fourth}`);    // 출력: None

 

4. 함수의 다중 반환 값 처리

JavaScript 함수는 하나의 값만 반환할 수 있지만, 값을 배열로 묶어 반환하면 구조 분해를 통해 여러 변수에 깔끔하게 담을 수 있습니다. 이는 특히 비동기 처리(Promise.all)나 간단한 유틸리티 함수에서 유용합니다.

// 함수가 결과 상태와 데이터를 배열로 반환
function fetchCoordinates() {
  return [true, 37.5665, 126.9780]; // [성공 여부, 위도, 경도]
}

const [success, latitude, longitude] = fetchCoordinates();

if (success) {
  console.log(`좌표: 위도 ${latitude}, 경도 ${longitude}`);
  // 출력: 좌표: 위도 37.5665, 경도 126.978
}

 

5. Spread/Rest 문법과의 결합 (Rest Elements)

배열 구조 분해 시 마지막에 Rest 문법 (...)을 사용하면, 나머지 모든 요소를 모아 새로운 배열로 할당할 수 있습니다.

const scores = [95, 90, 88, 75, 60, 55];

// 첫 두 요소(최상위 점수)를 분해하고, 나머지를 'otherScores' 배열로 모읍니다.
const [highest, second, ...otherScores] = scores;

console.log(`최고 점수: ${highest}`);           // 출력: 95
console.log(`나머지 점수 목록: ${otherScores}`); // 출력: 88,75,60,55

 

4. Spread (...) / Rest (...)

JavaScript에서 점 세 개 (...) 문법은 매우 강력하고 유용하지만, 사용되는 위치에 따라 두 가지 완전히 다른 역할(Spread와 Rest)을 수행합니다.

 

🔷 Spread 문법 (Spread Syntax) - '펼치기'

Spread는 '퍼뜨리다' 또는 '펼치다'라는 뜻 그대로, 이터러블 객체(주로 배열)나 일반 객체의 요소를 개별적인 요소로 확장하는 역할을 합니다. 새로운 배열이나 객체를 만들거나, 함수의 인수로 배열 요소를 전달할 때 사용됩니다.

 

1. 배열 복사 및 병합 (Merging Arrays)

Spread 문법의 가장 흔한 용도는 기존 배열을 변경하지 않고(불변성 유지) 새로운 배열을 생성하거나 배열을 병합하는 것입니다.

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

// 1. 배열 복사 (얕은 복사): arr1의 모든 요소를 개별적으로 펼쳐서 새 배열에 넣음
const arrCopy = [...arr1];
console.log(arrCopy); // [1, 2, 3]

// 2. 배열 병합: arr1과 arr2의 요소를 모두 펼쳐서 하나의 새 배열로 만듦
const mergedArray = [...arr1, ...arr2, 7, 8];
console.log(mergedArray); // [1, 2, 3, 4, 5, 6, 7, 8]

 

2. 객체 복사 및 병합 (Merging Objects)

객체에 Spread 문법을 사용하면, 해당 객체의 모든 프로퍼티를 펼쳐서 다른 객체에 복사하거나 병합할 수 있습니다.

const defaults = { size: 'M', color: 'White', material: 'Cotton' };
const userOrder = { color: 'Blue', quantity: 2 };

// 객체 병합: defaults와 userOrder의 프로퍼티를 모두 펼쳐서 새 객체를 만듦
// *주의: 동일한 키(color)가 있으면 뒤에 오는 값이 앞선 값을 덮어씁니다.
const finalOrder = { ...defaults, ...userOrder, size: 'L' };

console.log(finalOrder);
// 출력: { size: 'L', color: 'Blue', material: 'Cotton', quantity: 2 }
// size는 'L'로, color는 'Blue'로 덮어씌워졌습니다.

 

🔷 Rest 프로퍼티/요소 (Rest Properties/Elements) - '모으기'

Rest는 '나머지'라는 뜻으로, 구조 분해 할당 시 사용되어 남은 모든 프로퍼티나 요소를 모아(Collect) 새로운 배열이나 객체로 만들어 주는 역할을 합니다.

 

📌 Rest 문법의 핵심 규칙

Rest 문법은 항상 구조 분해 할당의 가장 마지막에 위치해야 합니다. (나머지를 모두 모아야 하기 때문)

 

1. 객체 Rest 프로퍼티

구조 분해 할당 시, 특정 프로퍼티를 분해하고 나머지 프로퍼티를 모아서 새 객체에 할당합니다

const userData = {
  name: 'Sam',
  age: 25,
  city: 'New York',
  job: 'Designer',
  role: 'user'
};

// name과 age를 추출하고, 나머지를 'details' 객체로 모음
const { name, age, ...details } = userData;

console.log(name);     // 출력: Sam
console.log(age);      // 출력: 25
console.log(details);  // 출력: { city: 'New York', job: 'Designer', role: 'user' }

 

2. 배열 Rest 요소

배열 구조 분해 할당 시, 특정 요소를 분해하고 나머지 모든 요소를 모아 새 배열에 할당합니다

const scores = [90, 85, 95, 80, 75, 60];

// 첫 두 요소를 분해하고, 나머지를 'otherScores' 배열로 모음
const [highest, secondHighest, ...otherScores] = scores;

console.log(highest);       // 출력: 90
console.log(secondHighest); // 출력: 85
console.log(otherScores);   // 출력: [95, 80, 75, 60]

 

✔ 마무리

JavaScript에서 가장 많이 활용되는 데이터 구조인 객체(Object)와 배열(Array)을 중심으로 핵심 개념들을 정리했습니다.

▸ 객체(Object)는 키-값 쌍으로 이루어진 유연한 구조로, 실행 중에도 프로퍼티를 자유롭게 추가·수정·삭제할 수 있으며, 점 표기법과 대괄호 표기법으로 접근합니다. ES6 축약 문법과 Object.hasOwn()을 통해 더 간결하고 안전하게 다룰 수 있습니다.

▸ 배열(Array)은 순서를 가진 요소 리스트로, push/pop, shift/unshift로 쉽게 요소를 조작할 수 있습니다.

원본을 보존하는 slice()와 원본을 직접 변경하는 splice()의 차이를 이해하는 것은 매우 중요하며, findLast() 같은 최신 메서드도 활용하면 유용합니다.


▸ 구조 분해 할당(Destructuring)을 사용하면 객체/배열에서 필요한 값만 손쉽게 추출할 수 있고, 별칭이나 기본값도 설정할 수 있습니다.


▸ Spread/Rest 연산자(...)는 배열·객체 병합과 값 수집 등 현대 JavaScript에서 빠질 수 없는 문법으로, 더 간결하고 표현력 있는 코드 작성을 가능하게 합니다.


※ 게시된 글 및 이미지 중 일부는 AI 도구의 도움을 받아 생성되거나 다듬어졌습니다.

반응형

 

반응형