Skip to Content
WebJavaScriptECMAScript03. 배열·객체와 구조 분해로 할 일 목록 관리

이번 편의 결과물: add로 메모리 배열에 할 일 객체를 추가하고, list로 전체 목록을 출력합니다. · 다루는 개념: 배열 메서드(push/find), 객체 리터럴, 구조 분해, 스프레드/레스트

이 편에서 만드는 파일

todo-cli/ └── src/ └── index.js (~)

개념 정리

할 일 객체의 모양

todo-cli가 다루는 할 일 하나는 아래 필드를 가진 객체입니다. 이 모양은 08편에서 파일로 저장할 때도 그대로 씁니다.

필드타입설명
idnumber순번
titlestring할 일 내용
doneboolean완료 여부
tagsarray of string태그 목록
duestring 또는 null마감일 문자열, 없으면 null
createdAtstring생성 시각(ISO 문자열)

배열 메서드

메서드역할원본 배열 변경
push(item)끝에 항목 추가변경함
find(fn)조건에 맞는 첫 항목 반환변경 안 함
forEach(fn)항목마다 함수 실행(반환값 없음)변경 안 함

filter, sort, map은 04편에서 다룹니다.

구조 분해와 스프레드

구조 분해(destructuring)는 배열이나 객체에서 값을 꺼내 변수에 바로 담는 문법입니다.

const { tag, due } = flags; // 객체 구조 분해 const [first, ...rest] = todos; // 배열 구조 분해 + 레스트

스프레드(...)는 반대로 배열이나 객체를 펼쳐 새 값을 만듭니다. 원본을 바꾸지 않고 복사본을 만들 때 자주 씁니다.

const updated = { ...todo, done: true }; // todo는 그대로, updated만 done이 true

이 편에서 만드는 todos 배열은 프로그램이 끝나면 사라지는 메모리 배열입니다. 파일에 저장해 다음 실행에도 남기는 방법은 08편(비동기 파일 저장)에서 다룹니다.

실습

1. src/index.js 열기

02편에서 만든 인자 파싱 코드에 할 일 배열과 명령 처리 로직을 추가합니다.

2. 코드 작성

// src/index.js import { parseArgs } from './cli/parseArgs.js'; const todos = [ { id: 1, title: '리포트 제출', done: false, tags: ['work'], due: '2026-09-20', createdAt: new Date().toISOString(), }, { id: 2, title: '운동하기', done: true, tags: ['health'], due: null, createdAt: new Date().toISOString(), }, ]; function nextId(list) { const last = list[list.length - 1]; return last ? last.id + 1 : 1; } function addTodo(list, title, { tag, due } = {}) { const todo = { id: nextId(list), title, done: false, tags: tag ? [tag] : [], due: due ?? null, createdAt: new Date().toISOString(), }; list.push(todo); return todo; } function printList(list) { list.forEach(({ id, title, done, tags, due }) => { const mark = done ? '[x]' : '[ ]'; const tagText = tags.length > 0 ? tags.join(', ') : '없음'; const dueText = due ?? '없음'; console.log(`${mark} #${id} ${title} (태그: ${tagText}, 마감: ${dueText})`); }); } const argv = process.argv.slice(2); const { command, positional, flags } = parseArgs(argv); if (command === 'add') { const [title] = positional; const created = addTodo(todos, title, flags); console.log('추가됨:', created); printList(todos); } else if (command === 'list') { printList(todos); } else { console.log('알 수 없는 명령입니다:', command); }

addTodo의 두 번째 매개변수 { tag, due } = {}는 객체 구조 분해와 기본값을 함께 씁니다. flagstagdue가 없어도 undefined로 처리되어 오류가 나지 않습니다. printList에서도 배열 원소를 바로 { id, title, done, tags, due }로 구조 분해해서 씁니다.

3. 실행

node src/index.js list
node src/index.js add "포트폴리오 프로젝트 카드 6개 채우기" --tag portfolio

확인

  • list 실행 결과:
[ ] #1 리포트 제출 (태그: work, 마감: 2026-09-20) [x] #2 운동하기 (태그: health, 마감: 없음)
  • add 실행 결과(뒤 3줄은 방금 추가한 항목까지 포함한 전체 목록, createdAt 값은 실행 시각에 따라 달라집니다):
추가됨: { id: 3, title: '포트폴리오 프로젝트 카드 6개 채우기', done: false, tags: [ 'portfolio' ], due: null, createdAt: '(실행 시각)' } [ ] #1 리포트 제출 (태그: work, 마감: 2026-09-20) [x] #2 운동하기 (태그: health, 마감: 없음) [ ] #3 포트폴리오 프로젝트 카드 6개 채우기 (태그: portfolio, 마감: 없음)
  • add를 한 번 더 실행해도 처음 두 항목만 다시 나타납니다. 메모리 배열이 프로세스가 끝날 때마다 초기화되기 때문입니다.

직접 해보기

  1. findid가 2인 할 일을 찾아 콘솔에 출력하는 코드를 todos.find(...) 형태로 추가해봅니다.
  2. 배열 구조 분해로 todos의 첫 번째 항목과 나머지 항목을 const [first, ...rest] = todos;로 나눠 각각 출력해봅니다.

정답 보기

const found = todos.find((todo) => todo.id === 2); console.log('찾음:', found); const [first, ...rest] = todos; console.log('첫 항목:', first); console.log('나머지:', rest);

자주 하는 실수

증상원인고치는 법
add 실행 후 list로 다시 봐도 추가한 항목이 없음각 실행이 별도 프로세스라 메모리 배열이 초기화됨08편에서 파일 저장을 배우기 전까지는 정상 동작이다
tags.join에서 오류 발생tag 플래그를 안 줘서 tagsundefined가 됨tag ? [tag] : []처럼 기본값을 명시한다
구조 분해 시 Cannot destructure property of undefinedflags 자체가 undefined인 상태에서 분해 시도매개변수에 = {} 기본값을 붙인다

확인 문제

문제 14지선다
배열의 push 메서드에 대한 설명으로 옳은 것은?
문제 24지선다
const { tag, due } = flags; 코드에서 사용된 문법은?
문제 34지선다
const updated = { ...todo, done: true }; 의 결과로 옳은 것은?
문제 44지선다
addTodo 함수에서 { tag, due } = {} 처럼 기본값을 준 이유는?

참고 자료

Last updated on