textContet
프로퍼티는 HTML 마크업은 무시하고 텍스트만 반환
innerHTML
프로퍼티는 HTML 마크업이 포함된 문자열 반환<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello <span>world!</span></div>
</body>
<script>
// #foo 요소의 콘텐츠 영역 내의 HTML 마크업을 문자열로 취득한다.
console.log(document.getElementById('foo').innerHTML);
// "Hello <span>world!</span>"
</script>
</html>
innerHTML
프로퍼티에 문자열을 할당하면
요소 노드의 모든 자식 노드가 제거되고 할당한 문자열에 포함되어 있는 HTML 마크업이 파싱되어 요소 노드의 자식 노드로 DOM에 반영된다. (할당한 문자열대로 덮어 씌운다)<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello <span>world!</span></div>
</body>
<script>
// HTML 마크업이 파싱되어 요소 노드의 자식 노드로 DOM에 반영된다.
document.getElementById('foo').innerHTML = 'Hi <span>there!</span>';
</script>
</html>
innerHTML
프로퍼티 사용 예시<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li class="apple">Apple</li>
</ul>
</body>
<script>
const $fruits = document.getElementById('fruits');
// 노드 추가
$fruits.innerHTML += '<li class="banana">Banana</li>';
// 노드 교체
$fruits.innerHTML = '<li class="orange">Orange</li>';
// 노드 삭제
$fruits.innerHTML = '';
</script>
</html>
사용자로부터 입력받은 데이터를 그대로 innerHTML
프로퍼티에 할당하는 것은 크로스 사이트 스크립팅 공격에 취약하므로 위험하다.
HTML 마크업 내에 자바스크립트 악성 코드가 포함되어 있다면 파싱 과정에서 그대로 실행될 가능성이 있기 때문
<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello</div>
</body>
<script>
// innerHTML 프로퍼티로 스크립트 태그를 삽입하여 자바스크립트가 실행되도록 한다.
// HTML5는 innerHTML 프로퍼티로 삽입된 script 요소 내의 자바스크립트 코드를 실행하지 않는다.
document.getElementById('foo').innerHTML
= '<script>alert(document.cookie)</script>';
</script>
</html>
HTML5는 innerHTML
프로퍼티로 삽입된 script 요소 내의 자바스크립트 코드를 실행하지 않는다.
따라서 위의 예제는 HTML5 에서 동작하지 않는다.
하지만 아래처럼 크로스 사이트 스크립팅 공격이 가능하다.
<!DOCTYPE html>
<html>
<body>
<div id="foo">Hello</div>
</body>
<script>
// 에러 이벤트를 강제로 발생시켜서 자바스크립트 코드가 실행되도록 한다.
document.getElementById('foo').innerHTML
= `<img src="x" onerror="alert(document.cookie)">`;
</script>
</html>
이처럼 innerHTML
은 DOM 조작이 간단하고 직관적이라는 장점이 있지만 크로스 사이트 스크립팅 공격에 취약한 단점이 있다.
innerHTML의 또 다른 단점 1
innerHTML
프로퍼티에 HTML 마크업 문자열을 할당하는 경우 요소 노드의 모든 자식 노드를 제거하고 할당한 HTML 마크업 문자열을 파싱하여 DOM을 변경한다.<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li class="apple">Apple</li>
</ul>
</body>
<script>
const $fruits = document.getElementById('fruits');
// 노드 추가
$fruits.innerHTML += '<li class="banana">Banana</li>';
// $fruits.innerHTML = $fruits.innerHTML + '<li class="banana">Banana</li>';
// '<li class="apple">Apple</li>' + '<li class="banana">Banana</li>'
</script>
</html>
innerHTML의 또 다른 단점 2
insertAdjacentHTML(position, DOMString)
메서드는 기존 요소를 제거하지 않으면서 위치를 지정해 새로운 요소를 삽입한다.
insertAdjacentHTML
의 두 번째 인수로 전달한 HTML 마크업 문자열을 파싱하고 그 결과로 생성된 노드를 첫 번째 인수로 전달한 위치에 삽입하여 DOM에 반영한다.
<!DOCTYPE html>
<html>
<body>
<!-- beforebegin -->
<div id="foo">
<!-- afterbegin -->
text
<!-- beforeend -->
</div>
<!-- afterend -->
</body>
<script>
const $foo = document.getElementById('foo');
$foo.insertAdjacentHTML('beforebegin', '<p>beforebegin</p>');
$foo.insertAdjacentHTML('afterbegin', '<p>afterbegin</p>');
$foo.insertAdjacentHTML('beforeend', '<p>beforeend</p>');
$foo.insertAdjacentHTML('afterend', '<p>afterend</p>');
</script>
</html>
innerHTML
프로퍼티처럼 기존의 자식 노드를 모두 제거하고 처음부터 새롭게 생성하는 것이 아니고
기존 요소에는 영향을 주지 않고 새롭게 삽입될 요소만을 파싱하여 자식 요소로 추가하므로 더 빠르고 효율적이다.