JavaScript / document.write() 사용법과 문서가 지워지는 이유

document.write()는 HTML을 파싱하는 동안 문서 스트림에 문자열을 써서 요소를 만들 수 있는 오래된 메서드입니다. 페이지 로드가 끝난 뒤 호출하면 기존 문서가 지워질 수 있으므로 화면 갱신에는 사용하지 마세요. 새 코드에서는 createElement()와 replaceChildren() 등으로 필요한 위치의 DOM만 변경하는 것이 적합합니다.

문서 파싱 중에 쓰는 방식

document.write(markup1, markup2, ...)는 인수를 순서대로 이어 문서 스트림에 씁니다. 문자열은 일반 텍스트가 아니라 HTML로 파싱됩니다. 아래 예제의 스크립트는 HTML을 읽는 도중 실행되며 “Hello World” 문단을 두 문단 사이에 넣습니다.

<!doctype html>
<html lang="ko">
<head><meta charset="utf-8"><title>document.write 확인</title></head>
<body>
  <p>스크립트 앞 문단</p>
  <script>
    document.write('<p id="written">Hello ', 'World</p>');
  </script>
  <p>스크립트 뒤 문단</p>
</body>
</html>

파일을 document-write-legacy.html로 저장해 브라우저에서 열면 “스크립트 앞 문단”, “Hello World”, “스크립트 뒤 문단” 순서로 보입니다. 이는 파싱 중에 호출한 예제이므로, 버튼 클릭 이벤트에서 같은 코드를 호출하는 경우와 결과가 다릅니다.

로드 뒤 호출과 보안 문제

문서 스트림이 닫힌 뒤 이벤트 처리기 등에서 document.write()를 호출하면 문서가 다시 열리고 기존 내용이 사라질 수 있습니다. 비동기 스크립트에서는 호출이 무시되는 경우도 있습니다. 환경과 실행 시점에 따라 결과가 달라서 디버깅하기 어렵습니다.

또한 write()는 입력 문자열을 HTML로 해석합니다. 사용자 입력을 그대로 전달하면 교차 사이트 스크립팅(XSS) 위험이 생깁니다. 기존 코드의 동작을 이해하는 용도로만 예제를 보고, 입력한 텍스트를 표시할 때는 textContent를 사용하세요. MDN의 document.write() 문서는 새 프로젝트에서 사용하지 말 것을 권합니다.

대체 예제: 특정 요소만 갱신하기

다음 코드를 dom-output.html로 저장해 엽니다. 텍스트를 입력하고 “표시”를 누르면 새 문단을 만들어 결과 영역에 넣습니다. “지우기”는 결과 영역만 비우고 나머지 페이지는 유지합니다.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>문서 일부에 텍스트 표시하기</title>
</head>
<body>
<label for="message">표시할 텍스트</label>
<input id="message" value="Hello World">
<button id="show" type="button">표시</button>
<button id="clear" type="button">지우기</button>
<div id="output" aria-live="polite"></div>
<script>
const input = document.querySelector('#message');
const output = document.querySelector('#output');

document.querySelector('#show').addEventListener('click', () => {
  const paragraph = document.createElement('p');
  paragraph.textContent = input.value;
  output.replaceChildren(paragraph);
});
document.querySelector('#clear').addEventListener('click', () => {
  output.replaceChildren();
});
</script>
</body>
</html>

기본 입력의 결과는 “Hello World” 문단입니다. 입력을 <b>Hello</b>로 바꿔도 굵은 글씨가 아니라 태그 문자 그대로 표시됩니다. textContent가 사용자 입력을 HTML로 해석하지 않기 때문입니다. 줄바꿈을 추가하는 이전 방식이 궁금하면 document.writeln()의 줄바꿈 동작도 확인할 수 있습니다.