← JavaScript 강의 목록으로
🎯
DOM
중급 · 선수: 16_async_await

17. DOM 선택과 조회

브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.

DOMquerySelectorgetElementById조회
소요 시간
약 1시간
난이도
📊 중급
선수 조건
🎯 단원 16
결과물
브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.

이 강의에서 배우는 것

  • 1DOM 트리의 개념을 이해한다.
  • 2`querySelector`, `querySelectorAll`, `getElementById` 로 요소를 선택한다.
  • 3`getAttribute`, `dataset` 으로 속성을 읽는다.
  • 4`textContent` 와 `innerHTML` 의 차이(특히 XSS)를 안다.
  • 5부모/자식/형제 노드를 탐색한다.

소개

브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.

핵심 개념

1. DOM 이란?

브라우저는 HTML 을 파싱해 DOM(Document Object Model) 트리를 만듭니다. 자바스크립트는 이 트리를 읽고 수정해 화면을 바꿉니다.

2. 요소 선택

javascript
const title = document.querySelector("#title");           // 첫 매칭
const items = document.querySelectorAll(".item");         // NodeList
const byId = document.getElementById("title");

`querySelector` 는 CSS 선택자를 그대로 받습니다. `querySelectorAll` 은 정적인 NodeList 를 돌려주므로 forEach 가 가능합니다.

3. 속성 조회

javascript
const link = document.querySelector("a");
link.getAttribute("href");
link.href;                  // DOM 프로퍼티
link.dataset.userId;        // data-user-id 속성

4. textContent vs innerHTML

`textContent` 는 단순 텍스트로 읽고/쓰기 때문에 안전합니다. `innerHTML` 은 HTML 문자열을 파싱하므로 사용자 입력을 그대로 넣으면 XSS 공격에 노출됩니다. 외부 입력은 항상 `textContent` 또는 sanitize 후 사용합니다.

5. 트리 탐색

javascript
el.parentElement;
el.children;
el.firstElementChild;
el.nextElementSibling;

핵심 예제

파일다루는 내용
index.html예제용 HTML 페이지
01_query_selector.jsquerySelector/All 사용
02_attributes.jsgetAttribute / dataset
03_text_html.jstextContent vs innerHTML
04_nested.js부모/자식/형제 탐색

src/01_query_selector.js

javascript
/**
 * querySelector / querySelectorAll / getElementById 비교.
 */
const title = document.querySelector("#title");
console.log("title:", title.textContent);

const items = document.querySelectorAll(".item");
console.log("아이템 개수:", items.length);
items.forEach((el) => console.log("-", el.textContent));

const byId = document.getElementById("msg");
console.log("msg:", byId.textContent);

src/02_attributes.js

javascript
/**
 * 속성과 dataset 읽기.
 */
const link = document.querySelector("#link");
console.log("href(attr):", link.getAttribute("href"));
console.log("href(prop):", link.href);

document.querySelectorAll(".item").forEach((el) => {
  console.log("id =", el.dataset.id, ", text =", el.textContent);
});

src/03_text_html.js

javascript
/**
 * textContent 와 innerHTML 의 차이.
 * 사용자 입력을 innerHTML 에 그대로 넣으면 XSS 위험이 있습니다.
 */
const msg = document.querySelector("#msg");
console.log("textContent:", msg.textContent);
console.log("innerHTML:", msg.innerHTML);

msg.textContent = "<b>안전</b>";
console.log("이후 textContent:", msg.textContent);

src/04_nested.js

javascript
/**
 * 부모/자식/형제 노드 탐색.
 */
const list = document.querySelector("#list");
console.log("자식 수:", list.children.length);
console.log("첫 자식:", list.firstElementChild.textContent);
console.log("두 번째 자식:", list.firstElementChild.nextElementSibling.textContent);
console.log("부모 태그:", list.parentElement.tagName);

src/index.html

html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>DOM 선택과 조회</title>
  </head>
  <body>
    <h1 id="title">DOM 예제</h1>
    <ul id="list">
      <li class="item" data-id="1">사과</li>
      <li class="item" data-id="2">바나나</li>
      <li class="item" data-id="3">체리</li>
    </ul>
    <a href="https://example.com" id="link">예제 링크</a>
    <p id="msg">Hello</p>

    <script src="01_query_selector.js"></script>
    <script src="02_attributes.js"></script>
    <script src="03_text_html.js"></script>
    <script src="04_nested.js"></script>
  </body>
</html>

자주 하는 실수

  1. 스크립트를 `<head>` 에서 로드해 DOM 이 아직 없는 상태에서 접근.
  2. `querySelectorAll` 결과를 배열로 착각해 `.map` 직접 호출 (Array.from 필요).
  3. `innerHTML` 에 사용자 입력을 그대로 삽입.
  4. `getAttribute("class")` 와 `el.className` 의 미묘한 차이 무시.
  5. id 가 같은 요소가 여러 개일 때의 동작에 의존.

FAQ

Q1. getElementById 와 querySelector("#id") 중 무엇이 좋나요?

성능 차는 미미합니다. 일관성을 위해 querySelector 만 써도 됩니다.

Q2. NodeList 와 HTMLCollection 의 차이?

NodeList 는 정적(또는 라이브), HTMLCollection 은 항상 라이브이며 forEach 가 없습니다.

Q3. dataset 의 키 이름 규칙?

data-user-id 는 dataset.userId 로 카멜케이스 변환됩니다.

과제

HTML 페이지에서 특정 클래스의 모든 항목을 선택해 목록을 콘솔에 출력하세요.

homework/README.md

HTML 의 `.fruit` 항목들을 모두 선택해 다음을 출력하세요.

  1. 각 항목의 텍스트
  2. data-color 속성 값

답안은 `answer/homework_01.html` 과 `answer/homework_01.js` 를 참고하세요.

homework/answer/homework_01.html

html
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>과제 17-1</title>
  </head>
  <body>
    <ul id="fruits">
      <li class="fruit" data-color="red">사과</li>
      <li class="fruit" data-color="yellow">바나나</li>
      <li class="fruit" data-color="purple">포도</li>
    </ul>
    <script src="homework_01.js"></script>
  </body>
</html>

homework/answer/homework_01.js

javascript
/**
 * .fruit 요소들의 텍스트와 색상 속성을 출력합니다.
 */
const fruits = document.querySelectorAll(".fruit");
fruits.forEach((el) => {
  console.log(`${el.textContent} -> ${el.dataset.color}`);
});

다음 단원

[18_DOM_조작](../18_DOM_조작/) — 요소 만들기/추가/삭제

예제 코드 / 강의 자료

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

GitHub에서 보기 ↗