그럼에도 불구하고

👨‍💻

[JavaScript] innerHTML, innerText, textContent 차이 + insertAdjacentHTML 본문

JavaScript/JavaScript basics

[JavaScript] innerHTML, innerText, textContent 차이 + insertAdjacentHTML

zenghyun 2023. 2. 16. 22:36

 

 

 

innerHTML, innerText, textContent 속성은 텍스트를 읽어오고 설정할 수 있다는 점에서 비슷해 보이지만, 조금씩 다른 차이가 있다.

 

그 차이에 대해 알아보자 :)

 


 

[ innerHTML ]

 

innerHTML은 'Element'의 속성으로, element내에 포함된 HTML 또는 XML 마크업을 가져오거나 태그와 함께 입력하여 내용을 직접 설정할 수 있다. 

 

즉, innerHTML을 사용하면 내부 HTML 코드를 JavaScript 코드에서 새 내용으로 쉽게 변경할 수 있는 것이다.

 

1
2
3
4
5
6
7
8
// html 코드와 함께 작성 가능
document.documentElement.innerHTML = "<p>innerHTML test입니다.</p>"
// 스타일 적용
document.documentElement.innerHTML = 
  "<span style='color:blue'>innerHTML style test입니다.</span>"
 
// 이런 식으로 빈 문자열을 넣으면 body의 전체 내용을 지울 수 있다.
document.body.innerHTML = "";
cs

 

innerHTML은 유용한 메서드이고, 자주 사용하지만 치명적인 단점을 가지고 있다.

 


 

※ innerHTML의 단점

MDN에 따르면 innerHTML은 XSS(Cross-Site-Scripting) 공격에 취약하다는 약점을 갖고 있다고 한다.

 

XXS란?

XSS(Cross-Site-Scripting)은 악의적인 목적을 가진 이가 웹사이트에 악성 스크립트를 주입하는 행위를 말한다. 

 

사용자의 입력을 받기 위해 만들어진 input, textarea와 같은 창에서 누군가가 스크립트를 작성하고, 그 스크립트가 innerHTML과 연결되어 파싱을 거친 뒤 코드단에 주입되면, 관리자가 예상하지 못한 결과가 발생할 수 있다. 

 

스크립트 내용에 따라서 쿠키나 세션 토큰 등의 탈취가 가능해서, 이를 인증이나 세션관리에 사용하고 있는 사이트에 침입하거나 심각한 피해를 입힐 가능성이 있다.

 

 

 

 innerHTML의 성능과 대용

앞서 말했듯, innerHTML의 사용은 지양하는 것이 좋으며 일반 텍스트를 삽입 할 때는 Node.textContent를 사용하는 것이 권장된다. ( Node.textContent에 대해서는 아래에서 알아보자 :) ) 그렇다면, 더 나아가 innerHTML 대신 사용될 수 있는 문법들과 그에 대한 어떤 기대효과들이 있는지 알아보자.

세부적인 기능과 동작 방식은 다르지만 innerHTML 대신 사용할 수 있는 문법들은 innerText, textContent, insertAdjacentHTML 가 있을 것이다.

 

innerHTML 의 동작 방식은 element가 기존에 가지고 있던 자식 요소를 파싱 하고, 새 값으로 들어온 newDOMString 또한 파싱 하여 DocumentFragment 객체를 생성한다. 이렇게 파싱 된 객체를 element의 innerHTML에 넣어줌으로써 element의 DOM 요소가 새로운 모습으로 변하게 되는 과정을 가진다.

따라서 파싱을 거치는 innerHTML 은 강력한 만큼 성능상의 약점을 지니는데, 이때 위의 대체적으로 사용할 수 있는 문법들을 사용하면 성능적인 이점을 가져갈 수 있다.

 

일반 텍스트의 삽입만을 원할 경우에는 innerText, textContent 두 문법을 사용할 수 있지만, textContent는 원시 텍스트를 다루며 성능상의 이점을 더 취하기 때문에 textContent의 사용이 더 권장될 것이다.

 

HTML 요소를 직접적으로 삽입하고 싶다면, insertAdjacentHTML 을 innerHTML 대신 사용할 수 있는데, 보안상의 이슈가 해결되진 않지만 insertAdjacentHTML은 자식 요소의 파싱 과정이 생략되기 때문에 성능상 훨씬 더 좋은 우위를 차지한다.

 

[ insertAdjacentHTML ]

insertAdjacentHTML()메서드는 HTML or XML 같은 특정 텍스트를 파싱 하고, 특정 위치에 DOM tree 안에 원하는 node들을 추가한다. 이미 사용 중인 element는 다시 파싱 하지 않는다. 그러므로 element 안에 존재하는 element를 건드리지 않는다. (innerHtml과는 좀 다름). innerHtml보다 작업이 덜 드므로 빠르다.

 

insertAdjacentHTML()를 사용하면 시작 태그의 앞, 시작 태그의 뒤, 종료 태그 앞, 종료 태그 뒤에 노드를 삽입하는 것이 가능하다. 

 

element.insertAdjacentHTML(position, text);

 

position은 아래 있는 단어만 사용 가능하다.

 

● "beforebegin" : 타겟 요소의 전 (형제 레벨)에 생성된다. - 시작 태그의 앞 (형제 레벨로) 

 

● "afterbegin" : 타겟 요소 다음 (자식 요소)에 생성된다. - 시작 태그의 뒤 (자식 요소로)

 

● "beforebegin" : 타겟 요소 끝나는 태그 바로 직전 (자식 요소)에  요소를 생성 - 종료 태그의 앞 (자식 요소로) 

 

"afterend" : 타겟 요소의 끝나는 태그 바로 다음 (형제 레벨)에 요소를 생성 - 종료 태그 뒤 (형제 레벨로) 

 

 

사용 예시

 

1
2
3
4
5
6
// <div id="one">one</div>
var d1 = document.getElementById('one');
d1.insertAdjacentHTML('afterend''<div id="two">two</div>');
 
// At this point, the new structure is:
// <div id="one">one</div><div id="two">two</div>
cs

 

[ innerText ]

innerText는 'Element'의 속성으로, element 내에서 사용자에게 보이는 text값들을 가져오거나 설정할 수 있다.

 

1
2
3
4
5
6
// innerHTML과 달리 text값만 다루기 때문에 html태그 사용 불가능
document.documentElement.innerText = "innerText test 입니다."
 
// html태그를 넣으면 태그도 text값으로 인식하고 
// <p>innerText test 입니다.</p> 문자열 그대로 적용함.
document.documentElement.innerText = "<p>innerText test 입니다.</p>"
cs

 

※ innerHTML과 innerText 비교

1
2
3
4
5
6
7
8
9
const innerT = document.getElementById('innerT');
innerT.innerText = "<div style='color:red'>innerText test입니다.</div>";
console.log(innerT)
// 스타일 적용되지 않은 기본 폰트로 <div style='color:red'>innerText test입니다.</div> 출력
 
const innerH = document.getElementById('innerH');
innerH.innerHTML = "<div style='color:red'>innerHTML test입니다.</div>";
console.log(innerH)
// 스타일 적용된 빨간색 폰트로 innerHTML test입니다. 출력
cs

 

 

[ textContent ] 

textContent는 'Node'의 속성으로, 사용자에게 보여지는 text값만 읽어오는 innerText와는 달리 <script><style> 태그에 상관없이 해당 노드가 가지고 있는 텍스트 값들을 모두 읽어온다.

 

아래 예제를 통해 display:none로 숨겨진 텍스트를 어떻게 가져오는지 각 속성들의 차이점을 살펴보자.

 

HTML

 

1
2
3
4
<div id='content'>
  test 
  <span style='display:none'>innerText에서는 확인 불가 :) </span>
</div>
cs

 

Script 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div id='content'>
  test 
  <span style='display:none'>innerText에서는 확인 불가 :)</span>
</div>
 
const content = document.getElementById('content');
 
console.log(content.innerHTML);
// html 전체를 다 가져온다.
 
// test
// <span style='display:none'>innerText에서는 확인 불가 :)</span>
 
-----------------------------------------------------
  
console.log(content.innerText);
// 사용자에게 보여지는 텍스트만 가져옴
// 숨겨진 텍스트는 사용자에게 보여지지 않기 때문에 test만 가져옴
 
// test
 
-----------------------------------------------------
  
console.log(content.textContent);
// 숨겨진 텍스트까지 포함해서 텍스트값을 모두 다 가져옴
 
// test
// innerText에서는 확인 불가 :)
cs

 

 

 

 

 

REF: https://velog.io/@kim_unknown_/JavaScript-Difftext

      https://velog.io/@cks3066/innerHTML-%EC%9D%80-%EC%95%88%EC%A0%84%ED%95%9C%EA%B0%80

      https://developer.mozilla.org/ko/docs/Web/API/Element/insertAdjacentHTML

Comments