[JavaScript 시리즈 6편] 객체, 구조 분해, 모듈로 코드 정리하기

English version

데이터를 불러왔으면 이제는 파일과 책임을 나누어야 합니다. 객체(Object)는 관련 값을 묶는 상자, 구조 분해는 그 상자에서 필요한 값만 꺼내는 방법, 모듈은 파일끼리 역할을 나누는 시스템입니다. 이 장은 핵심(객체/구조 분해/모듈 기초)과 선택(서비스·페이지 분리 응용)으로 나뉘니, 우선 핵심 흐름부터 자리 잡으세요.

이번 글에서 새로 나오는 용어

  1. 구조 분해 할당: 객체나 배열에서 필요한 값만 골라 변수로 바로 꺼내 쓰는 문법입니다.
  2. 모듈: 기능별로 나눈 파일 묶음으로, 서로 import/export 하며 코드를 공유합니다.
  3. import/export: 다른 파일에서 함수를 가져오거나 내보내도록 연결해 주는 키워드입니다.
  4. BASE_URL: 여러 API 주소 앞에 공통으로 붙는 기본 경로를 변수로 뽑아둔 값입니다.

핵심 개념

  • 객체 리터럴: 중괄호로 묶은 키-값 쌍입니다. 하나의 사용자나 카드 정보처럼 맥락이 있는 데이터를 표현합니다.
  • 구조 분해 할당: 객체나 배열에서 원하는 값을 변수로 바로 꺼내는 문법입니다. 선언부가 짧아지고 함수 매개변수가 명확해집니다.
  • 모듈(import/export): 파일을 기능별로 나누고 서로 불러오는 표준 방식입니다. 브라우저와 Node가 모두 이해하는 ES Module을 사용합니다.
  • 공통 상수 분리: API 주소나 선택자 같은 값은 한 파일에서 정의해 여러 곳에서 재사용하면 유지보수가 쉬워집니다.

코드로 확인하기

먼저 단일 객체를 선언하고 필요한 값만 구조 분해하는 가장 작은 예시부터 살펴봅니다.

const laptop = { brand: "A사", model: "Air 13", price: 1200000 };
const { brand } = laptop;
console.log(`${brand} 노트북`);

➡️ "한 상자에서 하나만 꺼내 쓴다"는 느낌만 익혀 두면 다음 예제를 이해하기가 한결 쉽습니다.

const user = {
  name: "지윤",
  email: "[email protected]",
  preferences: {
    theme: "light",
    language: "ko",
  },
  greet() {
    console.log(`${this.name}님 안녕하세요`);
  },
};

const {
  name,
  preferences: { theme, language },
} = user;

중첩 구조 분해를 사용하면 한 줄로 필요한 속성만 꺼낼 수 있습니다. 즉, user.preferences.theme를 계속 타이핑하지 않고도 같은 값을 얻습니다.

function createGreeting({ name, language = "ko" }) {
  return language === "ko" ? `${name}님 안녕하세요` : `Hello ${name}`;
}

createGreeting({ name: "하람" });

함수 매개변수에서 직접 구조 분해를 하면 함수 안쪽이 훨씬 짧아집니다. “함수에 어떤 값이 꼭 필요한가?”가 선언부에서 바로 보입니다.

// utils/date.js
export function formatDate(date) {
  return new Intl.DateTimeFormat("ko", { dateStyle: "medium" }).format(date);
}

// components/post-card.js

export function renderPost({ title, createdAt }) {
  return `<article><h3>${title}</h3><time>${formatDate(createdAt)}</time></article>`;
}

이렇게 모듈로 나누면 날짜 포맷을 바꿀 때 utils/date.js만 고치면 됩니다. 핵심 요약: "공통 함수 → utils", "화면 조각 → components"처럼 폴더 이름으로 역할을 드러내면 협업할 때 길을 잃지 않습니다.

// services/api.js
const BASE_URL = "https://starter-api.example";

export async function fetchStudent({ id }) {
  const response = await fetch(`${BASE_URL}/students/${id}`);
  if (!response.ok) throw new Error("학생 정보를 불러오지 못했습니다");
  const { name, major, club } = await response.json();
  return { name, major, club };
}

// pages/profile.js

export async function renderProfile(id) {
  const { name, major } = await fetchStudent({ id });
  return `<h1>${name}</h1><p>${major}</p>`;
}

데이터·UI·페이지 파일을 분리하면 다른 팀원이 한 부분만 고쳐도 전체 흐름을 이해하기 쉬워집니다. 위 예제는 선택 심화로, 프로젝트가 커졌을 때 적용해도 늦지 않습니다.

왜 중요한가

  • 객체로 맥락을 묶으면 함수를 호출할 때 매개변수 순서를 기억하지 않아도 됩니다.
  • 구조 분해는 “이 함수가 어떤 값만 필요로 하는지”를 한눈에 보여 줍니다. 코드 리뷰에서 큰 도움이 됩니다.
  • 모듈은 상태 관리, UI 렌더링, API 호출을 파일별로 나누어 협업 충돌을 줄이고 프레임워크 전환 시에도 재사용하기 좋습니다.

실습

  • 핵심 따라 하기: todo 데이터를 객체 배열로 만들고, 구조 분해로 title, completed를 꺼내 리스트를 렌더링합니다.
  • 선택 확장하기: 프로젝트를 data.js, services.js, components.js 세 파일로 나누고 import/export를 설정합니다.
  • 디버깅: 일부러 잘못된 경로를 import해 에러 메시지를 확인한 뒤 경로를 고치고, 구조 분해 기본값을 빼서 undefined가 되는 상황을 기록합니다.
  • 완료 기준: 최소 세 개 모듈이 서로 import/export 하며 todo 렌더링 흐름을 완성하고, 함수 매개변수가 세 개 이하로 줄어들면 실습이 끝납니다.

마무리

객체와 구조 분해는 함수 선언부를 가볍게 만들고, 모듈은 파일 책임을 명확히 합니다. 다음 글에서는 이 구조를 활용해 상태와 렌더링을 연결하는 미니 프로젝트를 만들어 보겠습니다.

💬 댓글

이 글에 대한 의견을 남겨주세요