C
JavaScript/DOM/Lesson 14

이벤트 — *사용자 입력 반응*

1시간·theory
이 챕터
2/2

이벤트 — *사용자 입력 반응*

🎯 이 lesson 을 읽고 나면

이 lesson 을 다 읽고 나면 아래 3가지를 자신 있게 할 수 있습니다.

  • ✅ 이벤트 캡처링 · 버블링 · 위임 (delegation) 패턴
  • ✅ addEventListener cleanup 누락의 메모리 누수
  • ✅ debounce / throttle 의 적용 시점

학습 목표를 체크리스트로 두고 다 답할 수 있게 되면 lesson 을 닫으세요.

이벤트 시스템

핵심 한 줄

이벤트 = 사용자가 뭔가를 했을 때 발생하는 신호. 클릭·키 입력·스크롤·마우스 이동 등. JS 가 이 신호를 받아서 동작.

자주 쓰는 이벤트 10가지

이벤트언제
click클릭
dblclick더블 클릭
submit폼 제출
input입력 변경 (실시간)
change입력 완료 (focus 잃을 때)
keydown / keyup키 누름·뗌
focus / blur포커스 얻음·잃음
mouseover / mouseout마우스 진입·이탈
scroll스크롤
load / DOMContentLoaded페이지 로드 완료

이벤트 리스너

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

// 추가
const handler = (e) => console.log("클릭!");
btn.addEventListener('click', handler);

// 제거
btn.removeEventListener('click', handler);   // 같은 함수 참조 필요

> 💡 인라인 onclick="..."옛 방식. addEventListener 권장 — 여러 핸들러 가능·제거 가능.

이벤트 객체

javascript
input.addEventListener('input', (e) => {
    console.log(e.target.value);   // 현재 입력값
    console.log(e.type);            // 'input'
});

button.addEventListener('click', (e) => {
    console.log(e.target);          // 클릭된 요소
    console.log(e.clientX, e.clientY);  // 마우스 좌표
});

document.addEventListener('keydown', (e) => {
    console.log(e.key);             // 'Enter', 'Escape', 'a' 등
    if (e.key === 'Enter') submit();
    if (e.ctrlKey && e.key === 's') save();   // 단축키
});

기본 동작 방지

javascript
form.addEventListener('submit', (e) => {
    e.preventDefault();   // 페이지 새로고침 방지
    // 직접 처리
});

link.addEventListener('click', (e) => {
    e.preventDefault();   // 링크 이동 방지
    showModal();
});

이벤트 전파 — 버블링

html
<div id="parent">
    <button id="child">버튼</button>
</div>
javascript
const parent = document.querySelector('#parent');
const child  = document.querySelector('#child');

parent.addEventListener('click', () => console.log("parent"));
child .addEventListener('click', () => console.log("child"));

// 🖱️ 버튼(child) 클릭 시 출력 순서:
//   "child"     ← ① 클릭된 자기 자신 먼저
//   "parent"    ← ② 부모로 "버블링" 됨
//
// 💡 클릭은 자식에서 시작 → 부모 → 조상으로 "올라가며" 전파됨
//    이게 버블링. 부모도 자식의 클릭을 듣게 됨.

이벤트가 자식 → 부모위로 전파 됩니다. 이게 버블링.

중단:

javascript
child.addEventListener('click', (e) => {
    e.stopPropagation();   // 부모로 전파 X
});

이벤트 위임 — 효율적 패턴

html
<ul id="list">
    <li>아이템 1</li>
    <li>아이템 2</li>
    <li>아이템 3</li>
    <!-- 1000개 더 -->
</ul>

<li> 에 리스너 1000개? 비효율. 대신 부모에 1개:

javascript
document.querySelector('#list').addEventListener('click', (e) => {
    if (e.target.tagName === 'LI') {
        console.log(e.target.textContent);
    }
});

버블링 덕분에 부모가 자식 클릭 감지. 메모리·성능 모두 ↑. 동적으로 추가된 자식 도 자동으로 처리됨.

debounce·throttle — 과도 호출 방지

javascript
// 🐢 debounce — *마지막 호출 후 N ms 동안 잠잠하면* 그제서야 실행
function debounce(fn, ms) {
    let timer;                                    // 클로저로 timer 기억
    return (...args) => {
        clearTimeout(timer);                      // 이전 예약 취소!
        timer = setTimeout(() => fn(...args), ms); // 새로 N ms 뒤 예약
    };
}

// 사용 예: 검색 입력 — 300 ms 동안 추가 입력 없을 때만 fetch
const search = debounce((q) => {
    fetch(`/api/search?q=${q}`);
}, 300);

const input = document.querySelector('#search');
input.addEventListener('input', e => search(e.target.value));

// 📊 효과:
//   유저가 "hello" 라고 5글자 입력 → input 이벤트 5번 발생
//   debounce 없으면 → fetch 5번 호출 (낭비)
//   debounce 300ms → 마지막 입력 후 300ms 뒤 → fetch 1번

검색창에서 입력 끝나고 300ms 뒤 1번만 API 호출. 1000번 입력 → 1번 호출.

한 번 정리

  • addEventListener('type', handler) 가 표준
  • e.preventDefault() 로 기본 동작 차단
  • e.stopPropagation() 으로 버블링 차단
  • 이벤트 위임 으로 동적 자식 처리
  • debounce·throttle 로 성능 최적화

⚡ 직접 해보기 — 이벤트 시스템 (mock EventTarget)

브라우저 sandbox 제약으로 *mock EventTarget* 으로 addEventListener·dispatchEvent·preventDefault·버블링 시연.
✏️ JS 코드
📟 콘솔 출력
▶ 실행 버튼을 눌러보세요
⚠️ 브라우저 샌드박스에서 실행 — console.log()만 지원, alert/fetch 불가

🤖 AI 에게 이렇게 요청해보세요

이 lesson 의 개념을 알면 AI 에게 구체적으로 지시할 수 있습니다. 막연한 "고쳐줘" 가 아니라 어휘를 가진 요청 — 그게 토큰 절약의 출발점입니다.

  • "이 클릭 이벤트에 debounce 300ms 적용해줘"
  • "이 이벤트 핸들러를 cleanup (return () => removeEventListener) 까지 추가해줘"

왜 이게 토큰을 줄이나

개념을 모를 땐 AI 답변을 받고도 "그게 뭐예요?" 를 다시 물어야 합니다. 그 "다시 물음" 이 토큰을 잡아먹습니다. 개념 한 번 익혀두면 대화가 한 번에 끝납니다.

먼저 읽으면 좋은 개념: DOM이란?
다음 추천: 이벤트 루프
이벤트 처리 - JavaScript