JavaScript DOM 조작 | 웹 페이지 동적으로 제어하기

JavaScript DOM 조작 | 웹 페이지 동적으로 제어하기

이 글의 핵심

JavaScript DOM 조작에 대한 실전 가이드입니다. 웹 페이지 동적으로 제어하기 등을 예제와 함께 상세히 설명합니다.

들어가며

DOM이란?

DOM (Document Object Model)은 HTML 문서를 트리 구조의 객체로 옮겨 둔 것입니다. 브라우저가 문서를 그리기 위한 내부 표현이며, JavaScript는 이 트리의 노드를 읽고 바꿔 화면과 동작을 갱신합니다.

<!DOCTYPE html>
<html>
  <head>
    <title>제목</title>
  </head>
  <body>
    <h1 id="title">안녕하세요</h1>
    <p class="content">내용</p>
  </body>
</html>

DOM 트리:

document
  └─ html
      ├─ head
      │   └─ title
      └─ body
          ├─ h1#title
          └─ p.content

DOM 트리 구조 조금 더 보기

  • document: 트리의 진입점입니다. document.documentElement<html>, document.body<body>입니다.
  • 노드(Node): 요소뿐 아니라 텍스트·주석도 노드입니다. 예: <p>안녕</p>에서 "안녕"텍스트 노드입니다.
  • 부모·자식·형제: 각 노드는 parentElement, children, nextElementSibling 등으로 트리 상의 위치를 따라갈 수 있습니다(아래 «기타 선택 메서드» 절 참고).
  • 렌더 트리와의 관계: 브라우저는 HTML을 파싱해 DOM을 만들고, CSS와 함께 화면에 그립니다. DOM을 바꾸면(텍스트·속성·자식 추가/삭제) 화면이 갱신됩니다.

실무에서는 개발자 도구 Elements 패널에서 트리를 펼치며 구조를 확인하는 습관이 중요합니다.


1. 요소 선택

getElementById

// ID로 선택 (가장 빠름)
const title = document.getElementById("title");
console.log(title.textContent);  // 안녕하세요

querySelector / querySelectorAll

// CSS 선택자 사용 (첫 번째 요소)
const title = document.querySelector("#title");
const content = document.querySelector(".content");
const firstP = document.querySelector("p");

// 모든 요소 선택
const allPs = document.querySelectorAll("p");
console.log(allPs.length);  // p 태그 개수

// 복잡한 선택자
const link = document.querySelector("div.container > a.link");
const items = document.querySelectorAll("ul li:nth-child(odd)");

// NodeList 순회
allPs.forEach(p => {
    console.log(p.textContent);
});

기타 선택 메서드

// 클래스로 선택
const elements = document.getElementsByClassName("content");

// 태그로 선택
const paragraphs = document.getElementsByTagName("p");

// 자식 요소
const parent = document.getElementById("parent");
const children = parent.children;  // HTMLCollection
const firstChild = parent.firstElementChild;
const lastChild = parent.lastElementChild;

// 형제 요소
const element = document.getElementById("myElement");
const next = element.nextElementSibling;
const prev = element.previousElementSibling;

// 부모 요소
const parent = element.parentElement;

2. 요소 조작

텍스트 변경

const title = document.getElementById("title");

// textContent: 순수 텍스트
title.textContent = "새로운 제목";

// innerHTML: HTML 포함 (XSS 주의!)
title.innerHTML = "새로운 <strong>제목</strong>";

// innerText: 화면에 보이는 텍스트 (스타일 고려)
title.innerText = "제목";

innerHTML vs textContent 실무 가이드

구분textContentinnerHTML
내용순수 텍스트만HTML 문자열을 파싱해 DOM에 반영
XSS사용자 입력을 넣어도 태그로 실행되지 않음신뢰할 수 없는 문자열을 넣으면 스크립트 삽입 위험
성능대체로 단순·안전HTML 파싱 비용 + 보안 이슈

규칙: 사용자 입력이나 API 응답을 화면에 넣을 때는 **textContent**를 기본으로 하고, 정말 HTML이 필요하면 먼저 이스케이프하거나 DOMPurify 같은 라이브러리를 검토합니다. 리스트를 동적으로 만들 때는 **createElement + appendChild**가 innerHTML 문자열 조립보다 추적이 쉬운 경우가 많습니다.

// ✅ 안전: 텍스트만 표시
el.textContent = userInput;

// ⚠️ 위험: userInput에 <script>가 들어갈 수 있음
el.innerHTML = userInput;

속성 조작

const link = document.querySelector("a");

// 속성 가져오기
console.log(link.getAttribute("href"));

// 속성 설정
link.setAttribute("href", "https://google.com");
link.setAttribute("target", "_blank");

// 속성 제거
link.removeAttribute("target");

// 직접 접근
link.href = "https://google.com";
link.id = "myLink";
link.className = "link active";

// classList (클래스 조작)
link.classList.add("highlight");
link.classList.remove("active");
link.classList.toggle("selected");  // 있으면 제거, 없으면 추가
console.log(link.classList.contains("highlight"));  // true

스타일 변경

const box = document.getElementById("box");

// 인라인 스타일
box.style.color = "red";
box.style.backgroundColor = "yellow";
box.style.fontSize = "20px";

// 여러 스타일 한 번에
Object.assign(box.style, {
    color: "blue",
    backgroundColor: "lightgray",
    padding: "10px",
    borderRadius: "5px"
});

// 계산된 스타일 가져오기
const styles = window.getComputedStyle(box);
console.log(styles.color);  // rgb(0, 0, 255)

3. 요소 생성과 삭제

요소 생성

// 요소 생성
const div = document.createElement("div");
div.textContent = "새 요소";
div.className = "box";
div.id = "newBox";

// 속성 설정
div.setAttribute("data-id", "123");

// 추가
document.body.appendChild(div);  // body 끝에 추가

// 특정 위치에 추가
const container = document.getElementById("container");
const firstChild = container.firstElementChild;
container.insertBefore(div, firstChild);  // 첫 번째 자식 앞에

// insertAdjacentHTML
container.insertAdjacentHTML("beforeend", "<p>새 단락</p>");
// beforebegin: 요소 앞
// afterbegin: 첫 자식 앞
// beforeend: 마지막 자식 뒤
// afterend: 요소 뒤

요소 삭제

const element = document.getElementById("myElement");

// 방법 1: remove()
element.remove();

// 방법 2: removeChild()
const parent = element.parentElement;
parent.removeChild(element);

// 모든 자식 제거
const container = document.getElementById("container");
container.innerHTML = "";  // 간단하지만 이벤트 리스너 제거 안 됨

// 또는
while (container.firstChild) {
    container.removeChild(container.firstChild);
}

요소 복제

const original = document.getElementById("original");

// 얕은 복제 (자식 제외)
const shallowClone = original.cloneNode(false);

// 깊은 복제 (자식 포함)
const deepClone = original.cloneNode(true);

document.body.appendChild(deepClone);

4. 이벤트 처리

이벤트 리스너

const button = document.getElementById("myButton");

// 이벤트 리스너 추가
button.addEventListener("click", function(event) {
    console.log("클릭됨!");
    console.log("이벤트 타입:", event.type);
    console.log("타겟:", event.target);
});

// 화살표 함수
button.addEventListener("click", (e) => {
    console.log("클릭됨!");
});

// 이벤트 리스너 제거
function handleClick(e) {
    console.log("클릭!");
}

button.addEventListener("click", handleClick);
button.removeEventListener("click", handleClick);

// 한 번만 실행
button.addEventListener("click", () => {
    console.log("한 번만 실행");
}, { once: true });

이벤트 전파: 캡처링과 버블링

이벤트는 DOM 트리를 따라 두 단계로 전파됩니다.

  1. 캡처링(capturing): window → 대상 요소 방향(위에서 아래로).
  2. 타깃(target): 실제 이벤트가 발생한 요소.
  3. 버블링(bubbling): 대상 요소 → window 방향(아래에서 위로). 대부분의 이벤트는 버블링합니다.

addEventListener세 번째 인자로 캡처 단계에서만 실행할지 정합니다.

const outer = document.getElementById("outer");
const inner = document.getElementById("inner");

outer.addEventListener(
  "click",
  () => console.log("outer 캡처"),
  { capture: true }
);

inner.addEventListener("click", () => console.log("inner 타깃"));

outer.addEventListener("click", () => console.log("outer 버블"));
// inner 클릭 시 로그 순서(대표적): outer 캡처 → inner 타깃 → outer 버블
  • event.target: 실제로 이벤트가 발생한 가장 안쪽 요소.
  • event.currentTarget: 리스너가 붙은 요소(위임 시 부모일 수 있음).

버블링을 막으려면 event.stopPropagation()을 사용합니다(꼭 필요할 때만 — 상위 핸들러까지 막습니다).

주요 이벤트

// 마우스 이벤트
element.addEventListener("click", e => {});      // 클릭
element.addEventListener("dblclick", e => {});   // 더블클릭
element.addEventListener("mouseenter", e => {}); // 마우스 진입
element.addEventListener("mouseleave", e => {}); // 마우스 이탈
element.addEventListener("mousemove", e => {});  // 마우스 이동

// 키보드 이벤트
input.addEventListener("keydown", e => {
    console.log("키:", e.key);
    console.log("코드:", e.code);
    
    if (e.key === "Enter") {
        console.log("엔터 입력!");
    }
});

input.addEventListener("keyup", e => {});
input.addEventListener("keypress", e => {});  // deprecated

// 폼 이벤트
form.addEventListener("submit", e => {
    e.preventDefault();  // 기본 동작 막기
    console.log("폼 제출");
});

input.addEventListener("input", e => {
    console.log("입력값:", e.target.value);
});

input.addEventListener("change", e => {
    console.log("변경됨:", e.target.value);
});

// 윈도우 이벤트
window.addEventListener("load", () => {
    console.log("페이지 로드 완료");
});

window.addEventListener("resize", () => {
    console.log("창 크기:", window.innerWidth, window.innerHeight);
});

window.addEventListener("scroll", () => {
    console.log("스크롤 위치:", window.scrollY);
});

이벤트 객체

button.addEventListener("click", (event) => {
    // 이벤트 타입
    console.log(event.type);  // click
    
    // 타겟 요소
    console.log(event.target);  // 클릭된 요소
    console.log(event.currentTarget);  // 이벤트 리스너가 등록된 요소
    
    // 마우스 위치
    console.log(event.clientX, event.clientY);  // 뷰포트 기준
    console.log(event.pageX, event.pageY);      // 문서 기준
    
    // 기본 동작 막기
    event.preventDefault();
    
    // 이벤트 전파 중단
    event.stopPropagation();
});

이벤트 위임 (Event Delegation)

// ❌ 각 요소에 이벤트 등록 (비효율)
const items = document.querySelectorAll(".item");
items.forEach(item => {
    item.addEventListener("click", () => {
        console.log("클릭:", item.textContent);
    });
});

// ✅ 부모에 이벤트 등록 (효율적)
const list = document.getElementById("list");

list.addEventListener("click", (e) => {
    if (e.target.classList.contains("item")) {
        console.log("클릭:", e.target.textContent);
    }
});

// 동적 요소에도 작동
const newItem = document.createElement("li");
newItem.className = "item";
newItem.textContent = "새 항목";
list.appendChild(newItem);  // 자동으로 이벤트 적용됨

5. 실전 예제

예제 1: To-Do 리스트

<!DOCTYPE html>
<html>
<head>
    <title>To-Do 리스트</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 500px;
            margin: 50px auto;
        }
        .todo-item {
            padding: 10px;
            margin: 5px 0;
            border: 1px solid #ddd;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .completed {
            text-decoration: line-through;
            opacity: 0.6;
        }
        button {
            padding: 5px 10px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h1>To-Do 리스트</h1>
    
    <input type="text" id="todoInput" placeholder="할 일 입력">
    <button id="addBtn">추가</button>
    
    <div id="todoList"></div>
    
    <script>
        const input = document.getElementById("todoInput");
        const addBtn = document.getElementById("addBtn");
        const todoList = document.getElementById("todoList");
        
        // 할 일 추가
        function addTodo() {
            const text = input.value.trim();
            
            if (!text) {
                alert("할 일을 입력하세요!");
                return;
            }
            
            // 요소 생성
            const todoItem = document.createElement("div");
            todoItem.className = "todo-item";
            
            const span = document.createElement("span");
            span.textContent = text;
            
            const deleteBtn = document.createElement("button");
            deleteBtn.textContent = "삭제";
            
            todoItem.appendChild(span);
            todoItem.appendChild(deleteBtn);
            todoList.appendChild(todoItem);
            
            // 입력창 초기화
            input.value = "";
            input.focus();
        }
        
        // 이벤트 리스너
        addBtn.addEventListener("click", addTodo);
        
        input.addEventListener("keypress", (e) => {
            if (e.key === "Enter") {
                addTodo();
            }
        });
        
        // 이벤트 위임: 완료/삭제
        todoList.addEventListener("click", (e) => {
            const todoItem = e.target.closest(".todo-item");
            
            if (e.target.tagName === "SPAN") {
                // 완료 토글
                todoItem.classList.toggle("completed");
            } else if (e.target.tagName === "BUTTON") {
                // 삭제
                todoItem.remove();
            }
        });
    </script>
</body>
</html>

예제 2: 탭 UI

<!DOCTYPE html>
<html>
<head>
    <title>탭 UI</title>
    <style>
        .tabs {
            display: flex;
            border-bottom: 2px solid #ddd;
        }
        .tab {
            padding: 10px 20px;
            cursor: pointer;
            border: none;
            background: none;
        }
        .tab.active {
            border-bottom: 3px solid #007bff;
            color: #007bff;
        }
        .tab-content {
            padding: 20px;
            display: none;
        }
        .tab-content.active {
            display: block;
        }
    </style>
</head>
<body>
    <div class="tabs">
        <button class="tab active" data-tab="tab1">탭 1</button>
        <button class="tab" data-tab="tab2">탭 2</button>
        <button class="tab" data-tab="tab3">탭 3</button>
    </div>
    
    <div id="tab1" class="tab-content active">
        <h2>탭 1 내용</h2>
        <p>첫 번째 탭입니다.</p>
    </div>
    
    <div id="tab2" class="tab-content">
        <h2>탭 2 내용</h2>
        <p>두 번째 탭입니다.</p>
    </div>
    
    <div id="tab3" class="tab-content">
        <h2>탭 3 내용</h2>
        <p>세 번째 탭입니다.</p>
    </div>
    
    <script>
        const tabs = document.querySelectorAll(".tab");
        const contents = document.querySelectorAll(".tab-content");
        
        tabs.forEach(tab => {
            tab.addEventListener("click", () => {
                // 모든 탭 비활성화
                tabs.forEach(t => t.classList.remove("active"));
                contents.forEach(c => c.classList.remove("active"));
                
                // 클릭된 탭 활성화
                tab.classList.add("active");
                const targetId = tab.getAttribute("data-tab");
                document.getElementById(targetId).classList.add("active");
            });
        });
    </script>
</body>
</html>

예제 3: 모달 (Modal)

<!DOCTYPE html>
<html>
<head>
    <title>모달</title>
    <style>
        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            justify-content: center;
            align-items: center;
        }
        .modal.active {
            display: flex;
        }
        .modal-content {
            background: white;
            padding: 30px;
            border-radius: 10px;
            max-width: 500px;
        }
        .close {
            float: right;
            cursor: pointer;
            font-size: 24px;
        }
    </style>
</head>
<body>
    <button id="openModal">모달 열기</button>
    
    <div id="modal" class="modal">
        <div class="modal-content">
            <span class="close">&times;</span>
            <h2>모달 제목</h2>
            <p>모달 내용입니다.</p>
        </div>
    </div>
    
    <script>
        const openBtn = document.getElementById("openModal");
        const modal = document.getElementById("modal");
        const closeBtn = document.querySelector(".close");
        
        // 모달 열기
        openBtn.addEventListener("click", () => {
            modal.classList.add("active");
        });
        
        // 모달 닫기
        closeBtn.addEventListener("click", () => {
            modal.classList.remove("active");
        });
        
        // 배경 클릭 시 닫기
        modal.addEventListener("click", (e) => {
            if (e.target === modal) {
                modal.classList.remove("active");
            }
        });
        
        // ESC 키로 닫기
        document.addEventListener("keydown", (e) => {
            if (e.key === "Escape" && modal.classList.contains("active")) {
                modal.classList.remove("active");
            }
        });
    </script>
</body>
</html>

예제 4: 동적 리스트 (추가·삭제 패턴)

입력값으로 <li>를 만들고, 삭제 버튼createElement로 붙이거나 이벤트 위임으로 처리합니다. 아래는 위임만 사용하는 짧은 패턴입니다.

<ul id="itemList"></ul>
<input type="text" id="itemInput" placeholder="항목">
<button type="button" id="addBtn">추가</button>

<script>
  const list = document.getElementById("itemList");
  const input = document.getElementById("itemInput");
  const addBtn = document.getElementById("addBtn");

  function addItem() {
    const text = input.value.trim();
    if (!text) return;

    const li = document.createElement("li");
    li.textContent = text; // 텍스트만 (HTML 주입 방지)

    const del = document.createElement("button");
    del.type = "button";
    del.textContent = "삭제";
    del.dataset.action = "delete";

    li.appendChild(del);
    list.appendChild(li);
    input.value = "";
  }

  addBtn.addEventListener("click", addItem);

  list.addEventListener("click", (e) => {
    const btn = e.target.closest("button[data-action='delete']");
    if (!btn) return;
    btn.closest("li")?.remove();
  });
</script>

예제 5: 폼 검증 (클라이언트)

HTML5 required, pattern, type="email" 로 1차 검증을 하고, JavaScript로 메시지 표시·포커스를 보강합니다. 최종 검증은 서버에서 다시 해야 합니다.

<form id="signup" novalidate>
  <label>
    이메일
    <input type="email" id="email" name="email" required>
  </label>
  <span id="emailError" class="error" aria-live="polite"></span>

  <label>
    비밀번호 (8자 이상)
    <input type="password" id="password" name="password" minlength="8" required>
  </label>
  <span id="pwError" class="error" aria-live="polite"></span>

  <button type="submit">가입</button>
</form>

<script>
  const form = document.getElementById("signup");
  const email = document.getElementById("email");
  const password = document.getElementById("password");
  const emailError = document.getElementById("emailError");
  const pwError = document.getElementById("pwError");

  function validateEmailField() {
    emailError.textContent = "";
    if (!email.validity.valid) {
      emailError.textContent = email.validationMessage || "이메일 형식을 확인하세요.";
      return false;
    }
    return true;
  }

  function validatePasswordField() {
    pwError.textContent = "";
    if (password.value.length < 8) {
      pwError.textContent = "비밀번호는 8자 이상이어야 합니다.";
      return false;
    }
    return true;
  }

  email.addEventListener("blur", validateEmailField);
  password.addEventListener("blur", validatePasswordField);

  form.addEventListener("submit", (e) => {
    const okEmail = validateEmailField();
    const okPw = validatePasswordField();
    if (!okEmail || !okPw) {
      e.preventDefault();
      return;
    }
    // e.preventDefault(); 후 fetch()로 전송 등
    console.log({ email: email.value });
  });
</script>

6. 폼 처리

폼 이벤트

<form id="myForm">
    <input type="text" id="username" name="username" required>
    <input type="email" id="email" name="email" required>
    <input type="password" id="password" name="password" required>
    <button type="submit">제출</button>
</form>

<script>
    const form = document.getElementById("myForm");
    
    form.addEventListener("submit", (e) => {
        e.preventDefault();  // 페이지 새로고침 방지
        
        // FormData 사용
        const formData = new FormData(form);
        
        const data = {
            username: formData.get("username"),
            email: formData.get("email"),
            password: formData.get("password")
        };
        
        console.log(data);
        
        // 또는 직접 접근
        const username = document.getElementById("username").value;
        const email = document.getElementById("email").value;
        
        // 유효성 검사
        if (username.length < 3) {
            alert("사용자명은 3자 이상이어야 합니다");
            return;
        }
        
        // API 전송
        fetch("/api/register", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(data)
        })
        .then(response => response.json())
        .then(result => console.log(result))
        .catch(error => console.error(error));
    });
    
    // 실시간 유효성 검사
    const username = document.getElementById("username");
    
    username.addEventListener("input", (e) => {
        const value = e.target.value;
        
        if (value.length < 3) {
            username.style.borderColor = "red";
        } else {
            username.style.borderColor = "green";
        }
    });
</script>

7. 자주 하는 실수와 해결법

실수 1: DOMContentLoaded 전에 접근

// ❌ HTML 로드 전 실행
const button = document.getElementById("myButton");  // null!
button.addEventListener("click", () => {});  // TypeError

// ✅ DOMContentLoaded 대기
document.addEventListener("DOMContentLoaded", () => {
    const button = document.getElementById("myButton");
    button.addEventListener("click", () => {
        console.log("클릭!");
    });
});

// ✅ 또는 script를 body 끝에 배치

실수 2: innerHTML로 이벤트 리스너 제거

// ❌ innerHTML은 이벤트 리스너 제거
const container = document.getElementById("container");
const button = document.createElement("button");
button.textContent = "클릭";
button.addEventListener("click", () => console.log("클릭!"));
container.appendChild(button);

container.innerHTML = "";  // 이벤트 리스너도 제거됨

// ✅ removeChild 사용
while (container.firstChild) {
    container.removeChild(container.firstChild);
}

실수 3: 이벤트 전파

// 이벤트 버블링
<div id="parent">
    <button id="child">버튼</button>
</div>

document.getElementById("parent").addEventListener("click", () => {
    console.log("부모 클릭");
});

document.getElementById("child").addEventListener("click", (e) => {
    console.log("자식 클릭");
    // e.stopPropagation();  // 전파 중단
});

// 버튼 클릭 시:
// 자식 클릭
// 부모 클릭 (버블링)

8. 연습 문제

문제 1: 카운터

증가/감소 버튼이 있는 카운터를 만드세요.

<div id="counter">
    <button id="decrease">-</button>
    <span id="count">0</span>
    <button id="increase">+</button>
</div>

<script>
    let count = 0;
    const countSpan = document.getElementById("count");
    
    document.getElementById("increase").addEventListener("click", () => {
        count++;
        countSpan.textContent = count;
    });
    
    document.getElementById("decrease").addEventListener("click", () => {
        count--;
        countSpan.textContent = count;
    });
</script>

문제 2: 동적 리스트

입력한 항목을 리스트에 추가하고 삭제할 수 있게 하세요.

<input type="text" id="itemInput">
<button id="addItem">추가</button>
<ul id="itemList"></ul>

<script>
    const input = document.getElementById("itemInput");
    const addBtn = document.getElementById("addItem");
    const list = document.getElementById("itemList");
    
    function addItem() {
        const text = input.value.trim();
        if (!text) return;
        
        const li = document.createElement("li");
        li.innerHTML = `
            ${text}
            <button class="delete">삭제</button>
        `;
        
        list.appendChild(li);
        input.value = "";
    }
    
    addBtn.addEventListener("click", addItem);
    
    input.addEventListener("keypress", (e) => {
        if (e.key === "Enter") addItem();
    });
    
    // 이벤트 위임
    list.addEventListener("click", (e) => {
        if (e.target.classList.contains("delete")) {
            e.target.parentElement.remove();
        }
    });
</script>

정리

핵심 요약

  1. 요소 선택:

    • getElementById(): ID로 선택
    • querySelector(): CSS 선택자
    • querySelectorAll(): 모든 요소
  2. 요소 조작:

    • 텍스트: textContent(기본), innerHTML(신뢰할 수 있는 입력만)
    • 속성: getAttribute(), setAttribute()
    • 스타일: style, classList
  3. 요소 생성/삭제:

    • 생성: createElement()
    • 추가: appendChild(), insertBefore()
    • 삭제: remove(), removeChild()
  4. 이벤트:

    • 등록: addEventListener()
    • 제거: removeEventListener()
    • 위임: 부모에 이벤트 등록
    • 전파: 캡처링(capture: true)과 버블링 이해
  5. 이벤트 객체:

    • event.target: 이벤트 발생 요소
    • event.preventDefault(): 기본 동작 막기
    • event.stopPropagation(): 전파 중단

베스트 프랙티스

  1. querySelector 우선 사용
  2. ✅ 이벤트 위임 활용
  3. DOMContentLoaded 대기
  4. innerHTML 대신 createElement (보안)
  5. ✅ 이벤트 리스너 정리

다음 단계

  • JavaScript 클래스
  • JavaScript 모듈
  • JavaScript 에러 처리

관련 글

  • JavaScript 시작하기 | 웹 개발의 필수 언어 완벽 입문
  • C++ Kafka 고급 활용 | 스트림 처리·트랜잭션·정확히 한 번 전달 완벽 가이드 [#52-6]
  • C++ 스크립팅 엔진 통합 | Lua·Python·JavaScript 바인딩 완벽 가이드 [#55-3]
  • C++ JavaScript 스크립팅 완벽 가이드 | V8 임베딩·컨텍스트·C++↔JS 바인딩 [실전]
  • HTML/CSS 시작하기 | 웹 개발 첫걸음