← 홈페이지 5강 목록으로
📋
EPISODE 05
리터럴 · 메서드/this · 구조분해 · 전개 · JSON · querySelector · createElement · classList · dataset · addEventListener · event 객체 · 버블링 · 위임 · Promise · async/await · fetch · try/catch

객체 · DOM 조작 · 이벤트 · 비동기 프로그래밍

객체 리터럴, 점/대괄호 표기법, 메서드와 this, 객체 배열 패턴, 구조분해할당, 전개 연산자, 그리고 JSON 직렬화를 익힙니다. DOM 요소를 선택(getElementById/querySelector), 변경(textContent vs innerHTML), 동적 추가/삭제(createElement, appendChild), classList 토글, data-* 속성을 익힙니다. addEventListener로 이벤트 등록, 자주 쓰는 이벤트(click/input/submit/keydown 등), event 객체의 target·key·preventDefault, 버블링, 그리고 이벤트 위임 패턴을 익힙니다. 동기 vs 비동기, setTimeout/setInterval, Promise의 then/catch, async/await로 비동기 코드를 동기처럼, fetch API로 외부 데이터 가져오기, 그리고 try/catch 에러 처리를 익힙니다.

JavaScriptobjectdestructuringJSONDOMclassListeventdelegationasync/awaitPromisefetch
소요 시간
⏱ 60분 + 60분 + 60분 + 60~90분
난이도
📊 초보~중급
선수 조건
🎯 js-04
결과물
객체 배열을 자유롭게 변형·집계·직렬화 / JavaScript로 페이지 내용을 동적으로 추가·삭제 / 동적으로 추가되는 요소까지 안전하게 처리하는 이벤트 시스템 / 외부 API 호출과 에러 처리를 갖춘 동적 페이지

이 강의에서 배우는 것

  • 1객체 리터럴로 데이터를 구조화한다
  • 2점/대괄호 표기법으로 속성에 접근한다
  • 3메서드와 this를 이해한다
  • 4구조분해와 전개로 깔끔한 코드를 쓴다
  • 5JSON.stringify / JSON.parse로 직렬화한다
  • 6getElementById/querySelector/querySelectorAll로 요소를 선택한다
  • 7textContent와 innerHTML의 보안 차이를 안다
  • 8createElement → appendChild로 요소를 동적으로 만든다
  • 9classList의 add/remove/toggle/contains를 사용한다
  • 10data-* 속성과 dataset으로 데이터를 저장·읽는다
  • 11addEventListener / removeEventListener로 이벤트를 등록·해제한다
  • 12click·input·submit·keydown·change 같은 자주 쓰는 이벤트를 안다
  • 13event.target / event.key / preventDefault를 활용한다
  • 14버블링을 이해하고 stopPropagation으로 막는다
  • 15이벤트 위임 패턴으로 효율적인 핸들러를 작성한다
  • 16동기와 비동기의 실행 순서 차이를 설명한다
  • 17Promise를 만들고 then/catch/finally로 처리한다
  • 18async/await으로 가독성 좋은 비동기 코드를 작성한다
  • 19fetch + response.json()으로 외부 데이터를 가져온다
  • 20try/catch + throw로 에러를 안전하게 처리한다

객체

객체 리터럴, 점/대괄호 표기법, 메서드와 this, 객체 배열 패턴, 구조분해할당, 전개 연산자, 그리고 JSON 직렬화를 익힙니다.

1. 객체 리터럴

javascript
const person = {
  name: "홍길동",
  age: 25,
  city: "서울",
  isStudent: false,
};

2. 속성 접근

javascript
// 점 표기법
console.log(person.name);
person.email = "h@a.com";   // 추가
person.age = 26;            // 수정
delete person.isStudent;    // 삭제

// 대괄호 표기법 (동적 키)
const key = "name";
console.log(person[key]);

const obj = { "first name": "길동" };
console.log(obj["first name"]);

3. 메서드와 this

javascript
const person = {
  name: "홍길동",
  age: 25,

  greet: function() {
    return `안녕하세요, ${this.name}입니다!`;
  },

  // 단축 메서드 (ES6+)
  getInfo() {
    return `${this.name} (${this.age}세)`;
  },
};

console.log(person.greet());
console.log(person.getInfo());
⚠️

화살표 함수는 자신만의 this를 갖지 않으므로 메서드에는 일반 함수를 사용합니다.

4. 객체 배열

javascript
const students = [
  { id: 1, name: "김철수", grade: "A", score: 95 },
  { id: 2, name: "이영희", grade: "B", score: 82 },
  { id: 3, name: "박민준", grade: "A", score: 91 },
];

const student = students.find(s => s.id === 2);
const aStudents = students.filter(s => s.grade === "A");
const avg = students.reduce((sum, s) => sum + s.score, 0) / students.length;

5. 구조분해할당

javascript
const person = { name: "홍길동", age: 25, city: "서울" };

const { name, age, city } = person;

// 변수명 변경
const { name: userName, age: userAge } = person;

// 기본값
const { email = "없음" } = person;

// 함수 매개변수
function greet({ name, age }) {
  return `${name}님은 ${age}세입니다.`;
}

6. 전개 연산자

javascript
const original = { name: "홍길동", age: 25 };

// 복사 (얕은)
const copy = { ...original };

// 합치기 (뒤가 우선)
const merged = { ...original, ...{ city: "서울", age: 30 } };

// 속성 추가/수정
const updated = { ...original, email: "h@a.com", age: 26 };

7. JSON

javascript
const person = { name: "홍길동", age: 25 };

// 객체 → JSON 문자열
const json = JSON.stringify(person);

// JSON 문자열 → 객체
const parsed = JSON.parse(json);

// 들여쓰기
console.log(JSON.stringify(person, null, 2));

DOM 조작

DOM 요소를 선택(getElementById/querySelector), 변경(textContent vs innerHTML), 동적 추가/삭제(createElement, appendChild), classList 토글, data-* 속성을 익힙니다.

1. 요소 선택

javascript
// ID로 단일 (가장 빠름)
const title = document.getElementById('title');

// CSS 선택자로 첫 번째
const btn = document.querySelector('.btn');
const input = document.querySelector('input[type="text"]');

// CSS 선택자로 모두 (NodeList)
const allItems = document.querySelectorAll('.item');
allItems.forEach(item => console.log(item.textContent));

2. textContent vs innerHTML

javascript
const div = document.querySelector('#content');

// textContent: 텍스트만 (HTML 무시, 안전)
div.textContent = '<b>굵게</b>';  // "<b>굵게</b>" 그대로 표시

// innerHTML: HTML 해석
div.innerHTML = '<b>굵게</b>';   // 굵게 표시
⚠️

innerHTML에 사용자 입력값을 직접 넣으면 XSS 공격 위험. 사용자 입력은 textContent를 사용하거나 별도 이스케이프 처리.

3. 요소 생성/추가/삭제

javascript
// 생성
const newDiv = document.createElement('div');
newDiv.textContent = '새 요소';
newDiv.className = 'card';

// 추가
const container = document.querySelector('#container');
container.appendChild(newDiv);    // 끝
container.prepend(newDiv);        // 앞
container.insertBefore(newDiv, container.firstChild);

// 삭제
container.removeChild(newDiv);
newDiv.remove();                  // 모던 방식

// 부모 참조
const parent = newDiv.parentElement;

4. classList

javascript
const box = document.querySelector('.box');

box.classList.add('active');
box.classList.add('highlight', 'large');  // 여러 개

box.classList.remove('active');

box.classList.toggle('dark-mode');  // 있으면 제거, 없으면 추가

if (box.classList.contains('active')) {
  console.log('active!');
}

5. dataset

html
<button data-id="42" data-user-name="홍길동" data-is-admin="true">
  클릭
</button>
javascript
const btn = document.querySelector('button');

// kebab-case → camelCase 자동 변환
console.log(btn.dataset.id);       // "42"
console.log(btn.dataset.userName); // "홍길동"
console.log(btn.dataset.isAdmin);  // "true"  ← 항상 문자열

// 쓰기
btn.dataset.count = 0;
btn.dataset.lastClicked = Date.now();

이벤트

addEventListener로 이벤트 등록, 자주 쓰는 이벤트(click/input/submit/keydown 등), event 객체의 target·key·preventDefault, 버블링, 그리고 이벤트 위임 패턴을 익힙니다.

1. addEventListener

javascript
const btn = document.querySelector('#myBtn');

btn.addEventListener('click', (event) => {
  console.log('클릭됨!', event.target);
});

// 이벤트 제거
function handleClick() { console.log('클릭'); }
btn.addEventListener('click', handleClick);
btn.removeEventListener('click', handleClick);

2. 자주 쓰는 이벤트

이벤트발생 시점대상
click마우스 클릭버튼·링크·카드
input값 변경 (실시간)input·textarea
change값 변경 후 포커스 이탈select·checkbox
submit폼 제출form
keydown키 누름input·document
keyup키 뗌input
mouseover/mouseout마우스 진입/이탈모든 요소
focus / blur포커스 받음/잃음input
DOMContentLoadedDOM 준비 완료document

3. event 객체

javascript
document.addEventListener('keydown', (event) => {
  console.log(event.key);       // "Enter", "a", "ArrowUp"
  console.log(event.code);      // "KeyA", "Enter", "Space"
  console.log(event.ctrlKey);   // true/false
  console.log(event.shiftKey);
});

// 폼 기본 동작 막기
document.querySelector('form').addEventListener('submit', (event) => {
  event.preventDefault();
  console.log('폼 처리');
});

btn.addEventListener('click', (event) => {
  console.log(event.target);          // 실제 클릭된 요소
  console.log(event.currentTarget);   // 이벤트가 등록된 요소
  console.log(event.clientX, event.clientY); // 마우스 좌표
});

4. 이벤트 버블링

html
<div id="outer">
  <div id="inner">
    <button id="btn">클릭</button>
  </div>
</div>
javascript
document.getElementById('btn').addEventListener('click', () => console.log('버튼'));
document.getElementById('inner').addEventListener('click', () => console.log('inner'));
document.getElementById('outer').addEventListener('click', () => console.log('outer'));

// 버튼 클릭 시: "버튼" → "inner" → "outer"

// 버블링 중단
document.getElementById('btn').addEventListener('click', (e) => {
  e.stopPropagation();
});

5. 이벤트 위임

부모 요소에 이벤트를 등록해 자식 요소들을 한꺼번에 처리. 동적으로 추가된 요소에도 자동 적용.

javascript
// 비효율: 각 버튼마다 등록
document.querySelectorAll('.item-btn').forEach(btn => {
  btn.addEventListener('click', handleClick);
});

// 효율: 부모에 위임
document.querySelector('#list').addEventListener('click', (event) => {
  if (event.target.classList.contains('item-btn')) {
    const itemId = event.target.dataset.id;
    console.log(`아이템 ${itemId} 클릭`);
  }
  if (event.target.classList.contains('delete-btn')) {
    event.target.closest('.item').remove();
  }
});

비동기 프로그래밍

동기 vs 비동기, setTimeout/setInterval, Promise의 then/catch, async/await로 비동기 코드를 동기처럼, fetch API로 외부 데이터 가져오기, 그리고 try/catch 에러 처리를 익힙니다.

1. 동기 vs 비동기

javascript
// 동기: 순서대로
console.log("1번");
console.log("2번");
console.log("3번");
// 1번 → 2번 → 3번

// 비동기: 완료 안 기다리고 다음으로
console.log("1번");
setTimeout(() => console.log("2번 (1초 후)"), 1000);
console.log("3번");
// 1번 → 3번 → 2번 (1초 후)

2. setTimeout / setInterval

javascript
// 한 번 실행
const timerId = setTimeout(() => {
  console.log("3초 후");
}, 3000);
clearTimeout(timerId);

// 반복 실행
const intervalId = setInterval(() => {
  console.log("1초마다");
}, 1000);

setTimeout(() => {
  clearInterval(intervalId);
}, 5000);

3. Promise

javascript
const myPromise = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve("성공!");
  } else {
    reject("실패!");
  }
});

myPromise
  .then(result => {
    console.log(result);
    return result + " 처리 완료";
  })
  .then(result => console.log(result))
  .catch(error => console.error(error))
  .finally(() => console.log("항상 실행"));

4. async / await

Promise를 더 간결하게 작성하는 문법입니다.

javascript
function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main() {
  console.log("시작");
  await delay(1000);
  console.log("1초 후");
  await delay(1000);
  console.log("2초 후");
}

main();

5. fetch API

Promise 방식

javascript
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error(error));

async/await 방식 (권장)

javascript
async function loadData() {
  try {
    const response = await fetch('https://api.example.com/data');

    if (!response.ok) {
      throw new Error(`HTTP 오류: ${response.status}`);
    }

    const data = await response.json();
    console.log(data);

  } catch (error) {
    console.error("실패:", error.message);
  }
}

6. JSON.parse / stringify

javascript
const user = { name: "홍길동", age: 25 };
const json = JSON.stringify(user);
const parsed = JSON.parse(json);

// localStorage와 자주 사용
localStorage.setItem('user', JSON.stringify(user));
const saved = JSON.parse(localStorage.getItem('user'));

7. try / catch 에러 처리

javascript
async function risky() {
  try {
    const response = await fetch('https://invalid-url.xyz');
    if (!response.ok) throw new Error(`서버 오류: ${response.status}`);
    const data = await response.json();
    return data;

  } catch (error) {
    console.error("오류:", error.message);
    return null;

  } finally {
    console.log("작업 종료 (성공/실패 무관)");
  }
}
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗

댓글 0

아직 댓글이 없습니다. 첫 댓글을 남겨 주세요.

댓글은 회원만 쓸 수 있습니다.

광고·욕설·비방·개인정보·불법 내용이 담긴 댓글은 숨기거나 지웁니다. 댓글은 닉네임과 함께 공개됩니다. 개인정보처리방침