[모던JS: 브라우저] 문서 Document (2)

KG·2021년 6월 10일
0

모던JS

목록 보기
28/47
post-thumbnail

Intro

본 포스팅은 여기에 올라온 게시글을 바탕으로 작성되었습니다.
파트와 카테고리 동일한 순서로 모든 내용을 소개하는 것이 아닌, 몰랐거나 새로운 내용 위주로 다시 정리하여 개인공부 목적으로 작성합니다.
중간중간 개인 판단 하에 필요하다고 생각될 시, 기존 내용에 추가로 보충되는 내용이 있을 수 있습니다.

React와 DOM 조작

해당 부분은 모던JS 페이지에서 설명하고 있는 부분은 아니지만 언급이 필요할 것 같아 추가하게 되었다. React뿐만 아니라 컴포넌트 구조의 리-렌더링 방식을 사용하는 프레임워크라면 대부분 해당 내용이 동일하게 적용될 수 있을 것 같다. 그렇지만 본인이 메인 스택으로 사용하는 라이버리가 React이기 때문에 이를 기준으로 언급하고자 한다.

해당 포스트에서 리액트를 비롯한 프론트엔드 3대장에 대해 소개한 바 있다. 리액트를 설명할 때 핵심이 되었던 부분은 리액트는 가상 DOM 을 구축하여 달라진 부분만 체크하여 리-렌더링 해주기 때문에 빠른 속도를 자랑한다는 점이었다. 여기서 말하는 가상 DOM은 실제하는 브라우저 DOM 객체가 아닌 추상화 된 개념이다. 즉 우리는 리액트에서는 직접적인 DOM에 대한 조작을 가급적 회피하고 있다는 것을 알 수 있다. DOM을 직접 조작하는 것은 가상 DOM 방식에 비해 매우 느리기 때문이다.

하지만 브라우저: 문서 챕터에서 다루는 대부분의 DOM 조작 방식은 해당 DOM에 직접적으로 수정을 가하는 방식이다. 즉 해당 방식을 리액트에서 곧이 곧대로 적용하여 DOM에 접근하여 화면을 재구성하는 것은 리액트의 철학과는 상당히 거리가 멀다는 것을 알 수 있다.

리액트에 대해 주구장창 설명하는 시간은 아니기 때문에, 최대한 간단하게만 짚고 넘어가보자. 리액트는 state의 값이 변할 때마다 리-렌더링이 발생한다. 따라서 해당 state의 값을 이용하여 간접적으로 대부분의 DOM 조작을 수행할 수 있다. 물론 화면의 리-렌더링과 별개로 한 번 만들어진 컴포넌트에서 이전 데이터를 유지하고 싶은 경우가 있다. 이때는 ref를 통해 데이터 유지가 가능하고, 또한 이를 이용해 DOM에 직접적으로 접근 역시 가능하다. 따라서 이번 챕터에서 다루는 DOM 조작 관련 기능은 리액트에서 사용하지 않는 방식이다.

공식문서에 의하면 사실 ref를 통해 DOM에 접근하는 것 역시 권장하지 않고 있다. 이 역시 DOM에 직접적인 연산을 가할 수 있기 때문이다.

공식문서에서는 ref의 바람직한 사용 사례로 다음을 소개한다. 아래의 경우는 직접적인 DOM 조작이 불가피한 경우이다.

  • 포커스, 텍스트 선택 영역, 혹은 미디어의 재생을 관리할 때
  • 애니메이션을 직접적으로 실행시킬 때
  • 서드 파티 DOM 라이브러리(ex. Chart.js)를 React와 같이 사용할 때

VanillaJS만 가지고 웹 페이지를 구현하는 것은 기본기를 다지거나 순수 학습의 의도가 아니라면 오늘날 대부분의 실무 환경에서는 사실상 찾아보기 어렵다. 그렇다면 굳이 여기서 다룰 내용을 알아야 할 필요가 있을까란 의문이 들 수 있다. 그렇지만 기본이 되는 내용은 항상 중요하다. 결국 자바스크립트를 기반으로 두고 있는 프레임워크를 비롯한 모든 라이브러리는 기본 자바스크립트의 문법과 제공하는 메서드를 통해 구현되기 마련이다.

만약 우리가 추후 담당하는 실무 환경의 프로젝트 레벨에서 유지 보수 문제가 발생하거나 예상치 못한 오류가 발생하는 경우엔 이를 해결하기 위해 매우 깊은 수준까지 해당 프레임워크 또는 라이브러리를 탐구해야 할 경우가 생길 수 있다. 이럴때 기본기가 탄탄하지 않다면 이런 일을 대처하기 아주 난감할 것이다. 이 점을 염두해두고 계속 이번 챕터와 이후 챕터에서 나올 내용들을 익혀나가보자.

getElement, querySelector로 요소 검색

요소들이 다닥다닥 가까이 붙어 있는 모양새라면 저번 챕터에서 언급했던 DOM 탐색 프로퍼티만으로도 충분히 접근과 조작을 수행할 수 있을 것이다. 그러나 요소들이 멀리 떨어진 경우, 또는 굉장히 복잡한 구조로 짜여진 HTML 문서 구조에서는 탐색 프로퍼티만으로 원하는 요소까지 접근하기 매우 까다로울 수 있다. 이번 챕터에서는 원하는 요소에 바로 접근할 수 있게 도와주는 메서드에 대해 알아보자.

1) document.getElementById 혹은 id

만약 요소에 id 속성이 있다면 위치에 상관없이 document.getElementById 메서드를 사용해서 접근할 수 있다. 또는 id 속성값을 그대로 딴 전역 변수를 이용해 접근도 가능하다.

<div id='elem'>
  <div id='elem-content'>Element</div>
</div>

<script>
  // getElementId() 메서드 사용
  let elem = document.getElementById('elem');
  elem.style.background = 'red';
  
  // id 속성의 전역변수 사용
  elem-conent.style.background = 'blue'
</script>

하지만 후자처럼 요소 id를 따서 자동으로 선언된 전역변수를 사용하는 경우엔 동일한 이름을 가진 변수가 선언될 때 무시된다는 점을 주의해야 한다.

<div id='elem'></div>

<script>
  let elem = 5;
  
  // elem은 더이상 <div id='elem'>을 참조하지 안음
  console.log(elem);
</script>

따라서 id를 따서 만들어진 전역변수를 요소 접근 시 사용하지 않는 것이 좋다. 이는 명세서의 내용을 구현해 만들어진 표준사항이긴 하지만, 오늘날 하위 호환성을 위해 남겨둔 기능이다. 이 같은 방식은 가독성이 좋지 않다는 점, 그리고 언제 어디서나 충돌 가능성이 발생할 수 있다는 점 때문에 오늘날 이 같은 접근 방식은 사용하지 않는다.

또한 id 프로퍼티는 유일무이해야 한다는 컨벤션이 있다. 이는 문법적으로 강제되는 사항은 아니지만 문서 내 요소 id 값이 중복되지 않도록 관리하는 것은 매우 중요하다. 같은 id를 가진요소가 여러 개 있는 경우 document.getElementById와 같은 메서드를 이용해 요소에 접근하려는 경우 반환값이 예측 불가하다.

getElementById 메서드는 항상 document 객체를 대상으로 해당 id를 가진 요소 노드를 찾는다는 것을 주의하자. document가 아닌 다른 요소 노드 객체에서는 호출할 수 없다.

2) querySelectorAll

elem.querySelectorAll(css)는 다재다능한 요소 검색 메서드이다. 이 메서드는 elem의 자식 요소 중 주어진 CSS 선택자에 대응하는 요소 모두를 반환한다. CSS 선택자를 활용할 수 있다는 점에서 굉장히 간편하게 원하는 요소에 접근이 가능하고 유용하게 사용할 수 있다.

let elements = document.querySelectorAll('ul > li:last-child');

또한 CSS 선택자 외에도 가상 클래스(pseudo-class) 역시 사용이 가능하다. document.querySelectorAll(':hover')를 통해 마우스 포인터가 위에 있는 요소 모두에 접근이 가능하다.

getElementById와는 다르게 querySelector...의 경우는 항상 document 객체 레벨에서 실행되지 않아도 된다. 하지만 보통의 경우 CSS 선택자를 활용하여 document 레벨에서 원하는 요소에 접근하고는 한다.

3) querySelector

elem.querySelector(css)는 주어진 CSS 선택자에 대응하는 요소 중 첫 번째 요소를 반환한다. 즉 위에서 살펴본 elem.querySelectorAll(css)[0]과 동일한 기능을 수행한다. 따라서 내가 찾아야 하는 요소가 단 하나라면 querySelector를 통해 더 빠르게 접근이 가능하다.

4) matches

앞서 소개한 메서드는 모두 DOM 검색을 통해 접근하고자 할 때 사용한다. elem.matches(css)는 검색이 아닌 주어진 CSS 선택자와 elem 요소가 서로 일치하는지에 대한 여부를 판단한다. 만약 둘이 서로 일치한다면 true, 그렇지 않은 경우엔 false를 반환한다. 요소가 담겨있는 배열 등을 순회해 원하는 요소만 걸러내고자 할 때 유용하게 사용할 수 있다.

<a href="http://example.com/file.zip">...</a>
<a hret="http://yr.as">...</a>

<script>
  for (let elem of document.body.children) {
    if (elem.matches(`a[href$="zip"]`)) {
      console.log(elem.href + "일치!!");
    }
  }  
</script>

5) closest

부모 요소, 부모 요소의 부모 요소 등 DOM 트리에서 특정 요소의 상위에 있는 요소들은 조상(ancestor)노드라고 한다. elem.closest(css) 메서드는 elem 자기 자신을 포함해 CSS 선택자와 일치하는 가장 가까운 조상 요소를 찾을 수 있게 도와준다.

closest 메서드는 해당 요소부터 시작해 DOM 트리를 한 단계씩 거슬러 올라가며 원하는 요소를 찾는다. CSS 선택자와 일치하는 요소를 찾는다면 검색을 중단하고 해당 요소를 반환한다.

<h1>목차</h1>

<div class="contents">
  <ul class="book">
    <li class="chapter">1장</li>
    <li class="chapter">2장</li>
  </ul>
</div>

<script>
  let chapter = document.querySelector('.chapter'); // LI

  alert(chapter.closest('.book')); // UL
  alert(chapter.closest('.contents')); // DIV

  alert(chapter.closest('h1')); // null(h1은 li의 조상 요소가 아님)
</script>

6) getElementsBy*

태그나 클래스이름을 통해 원하는 노드를 찾는 메서드도 있다. 하지만 보통 querySelector를 이용하는 것이 더 편리하고 문법도 간단하기 때문에 요즈음엔 이러한 메서드를 잘 사용하지 않는 편이다. 따라서 해당 메서드들의 이름과 기능만 간단히 살펴보고 넘어가자.

  • elem.getElementsByTagName(tag) : 주어진 태그에 해당하는 요소에 접근
  • elem.getElementsByClassName(className) : 주어진 클래스명에 해당하는 요소에 접근
  • document.getElementsByName(name) : 주어진 이름 속성에 해당하는 요소에 접근
    • name 프로퍼티는 위에서 살펴본 id 프로퍼티와 동일하게 document 객체를 기점으로 검색한다.
    • name 프로퍼티는 input 태그 등에서 제공되는 속성 중에 하나이다.

이때 getElementsBy* 시리즈는 요소 하나가 아닌 컬렉션을 반환한다는 점에 주의하자. 따라서 컬렉션을 순회하며 원하는 요소에 접근을 하도록 주의하자.

7) 살아있는 컬렉션

getElementsBy* 로 시작하는 모든 메서드는 live한 컬렉션을 반환한다. live한 컬렉션은 앞에서도 살펴본 것과 같이 문서에 변경이 있을 때마다 이를 자동 갱신하여 최신 상태를 유지함을 의미한다.

아래 예제를 보면 document.getElementsByTagName('div') 메서드를 통해 요소에 접근하고 있다. 첫 시점에서 div 태그의 개수는 1임을 알 수 있다. 그리고 두 번째 div 태그를 선언하고 다시 길이를 출력해보면 자동 갱신되어 2를 출력하고 있음을 확인할 수 있다.

<div>첫 번째 div</div>

<script>
  let divs = document.getElementsByTagName('div');
  alert(divs.length); // 1
</script>

<div>두 번째 div</div>

<script>
  alert(divs.length); // 2
</script>

반면 querySelector*의 경우엔 정적인 컬렉션을 반환한다. 어떤 변수에 컬렉션을 저장했다면, 해당 변수는 DOM에 어떤 업데이트가 발생하더라도 변화하지 않는다.

아래 예제에서 변수 divs는 처음에 document.querySelectorAll('div')을 실행하여 받은 반환값의 정보를 계속 유지하고 있는 것을 확인할 수 있다.

<div>첫 번째 div</div>

<script>
  let divs = document.querySelectorAll('div');
  alert(divs.length); // 1
</script>

<div>두 번째 div</div>

<script>
  alert(divs.length); // 1
</script>

주요 노드 프로퍼티

이번 챕터에서는 DOM 노드의 주요 프로퍼티는 어떤 것이 있는지 조금 더 세부적으로 살펴보자.

1) DOM 노드 클래스

DOM 노드는 종류에 따라 각각 다른 프로퍼티를 지원한다. 그런데 모든 DOM 노드는 공통 조상으로부터 만들어지기 때문에 노드 종류는 다르지만, 모든 DOM 노드는 공통된 프로퍼티와 메서드를 지원한다.

서로 다른 DOM 노드는 종류에 따라서 대응하는 내장 클래스가 다르다. 이러한 계층 구조 꼭대기에는 EventTarget 객체가 있는데 Node 객체가 이를 상속 받고, 나머지 다른 모든 DOM 노드가 Node 객체를 상속 받는 구조로 되어있다.

각 클래스에 대한 특징은 다음과 같다.

  • EventTarget : 이는 루트에 존재하는 추상 클래스다. 실제로는 이 클래스에 대응하는 객체가 생성되지 않는다. EventTarget이 모든 DOM 노드 상위에 있기 때문에 DOM의 모든 노드에서는 이벤트를 사용할 수 있다.

  • Node : 역시 추상 클래스로 DOM 노드의 베이스 역할을 한다. getter 역할을 하는 parentNode, nextSibling, childNodes 등의 주요 트리 탐색 기능을 제공한다. 해당 클래스에 대응하는 객체 역시 생성되지 않고 다른 노드들이 이를 상속하여 가져간다.

  • Element : DOM 요소 노드를 위한 베이스 클래스이다. nextElemnetSibling, children 그리고 getElementByTagName, querySelector 같이 요소 전용 탐색을 도와주는 프로퍼티나 메서드를 가지고 있다.

  • HTMLElement : HTML 요소 노드의 베이스 역할을 하는 클래스이다. 실제 HTML 요소에 대응하는 클래스의 부모 클래스이다.

    • HTMLInputElement : <input> 요소에 대응
    • HTMLBodyElement : <body> 요소에 대응
    • HTMLDivElement : <div> 요소에 대응
    • ...
    • 이외에 다른 클래스 역시 각 태그에 해당하는 고유 및 공통 프로퍼티와 메서드를 지원

이때 EventTarget 객체는 노드 계층 구조 트리에 가장 상위에 있지만, 이 역시 객체이기 때문에 Object 내장 클래스를 상속 받는다.

우리는 앞서 프로토타입과 클래스 파트에서 모든 객체는 constructor 프로퍼티를 가진다는 걸 살펴보았다. 이 특징을 이용하면 DOM 노드 클래스 이름을 확인할 수 있다.

console.log( document.body.constructor.name );
// HTMLBodyElement

또는 toString 내장 메서드를 이용할 수도 있다.

console.log( document.body );
// [object HTMLBodyElement]

상속 여부는 instanceof 연산자로 확인이 가능하다.

alert( document.body instanceof HTMLBodyElement ); // true
alert( document.body instanceof HTMLElement ); // true
alert( document.body instanceof Element ); // true
alert( document.body instanceof Node ); // true
alert( document.body instanceof EventTarget ); // true

지금까지 살펴본 바와같이 DOM 노드는 프로토타입을 기반으로 상속 관계를 갖는 일반 자바스크립트 객체라는 것을 알 수 있다. 브라우저 콘솔에서 console.dir 명령을 통해 이러한 관계를 쉽게 파악할 수 있다.

이 같은 클래스는 타입스크립트에서 태그의 타입을 추정할 때 쓰이기도 한다.

2) nodeType 프로퍼티

nodeType 프로퍼티는 DOM 노드의 타입을 알아내고자 할 때 쓰이는 다소 구식의 프로퍼티이다. 각 노드타입은 상수값을 가지고, 이 상수값으로 어떤 노드 타입을 가지는지 확인할 수 있다.

  • elem.nodeType === 1 : 요소 노드
  • elem.nodeType === 3 : 텍스트 노드
  • elem.nodeType === 9 : 문서 객체
  • 그 외의 상수값은 명세서에서 확인이 가능하다.

3) nodeName과 tagName

nodeNametagName으로 태그 이름을 확인할 수 있다.

alert( document.body.nodeName ); // BODY
alert( document.body.tagName ); // BODY

이 둘은 이름에서 보이는 것과 같이 다음과 같은 차이를 가진다.

  • tagName : 요소 노드에만 존재하는 프로퍼티
  • nodeName : 모든 노드에 존재하는 프로퍼티=
    • 요소 노드를 대상으로 호출 시 tagName과 같은 역할
    • 텍스트 노드, 주석 노드를 대상으로 호출 시 노드 타입을 나타내는 문자열 반환

따라서 요소 노드만 다루고 있는 환경을 보장할 수 있다면 두 프로퍼티엔 차이가 없기 때문에 항상 동일하게 동작한다.

이때 태그 이름은 XML 모드를 제외하고는 항상 대문자라는 점을 주의하자. 그러나 XML 모드는 오늘날 HTML 문서를 구축하는데 거의 사용되지 않는다.

4) innerHTML 으로 내용 조작하기

innerHTML 프로퍼티를 사용하면 요소 안의 HTML을 문자열 형태로 받아올 수 있다. 또한 요소 내 HTML을 수정하는 것 역시 가능하다. 실제로 요소 내의 내용을 수정할 때 innerHTML은 그 강력함으로 인해 상당히 많이 쓰이는 방법 중에 하나이다.

<body>
  <p>p 태그</p>
  <div>div 태그</div>

  <script>
    alert( document.body.innerHTML ); // 내용 읽기
    document.body.innerHTML = '새로운 BODY!'; // 교체
  </script>

</body>
<body>

  <script>
    document.body.innerHTML = '<b>test'; // 닫는 태그를 잊음
    alert( document.body.innerHTML ); // <b>test</b> (자동으로 수정됨)
  </script>

</body>

이때 스크립트 <script>의 경우엔 innerHTML을 사용해 삽입하더라도 HTML 문서의 일부만 될 뿐 실제 실행은 되지 않는다는 점을 주의하자. 이는 브라우저의 보안 문제를 위해 고안된 최소한의 보안 장치이다. 과거부터 오늘날까지 브라우저에서 발생하는 대부분의 해킹 공격 방식은 스크립트 파일을 교묘하게 추가하여 일어났기 때문이다.

elem.innerHTML += <div>hello</div> 와 같이 innerHTML을 사용해 요소에 HTML을 추가하는 경우엔 주의해야 할 점이 있다. 이 경우엔 요소가 추가되는 것이 아니라 내용을 덮어쓰게 된다. 즉 위의 과정을 풀어쓰면 다음과 같다.

elem.innerHTML = elem.innerHTML + '...';

따라서 innerHTML += ... 와 같은 동작은 1. 기존 내용을 삭제함과 동시에 2. 기존 내용과 새로운 내용을 합쳐 새로운 내용을 쓰게 되는 동작과도 같다.

텍스트라던가 간단한 마크업 구조라면 이 같은 일이 큰 문제가 되지 않을 지도 모른다. 그렇지만 기존 내용을 지우고 새로운 내용으로 다시 작성한다는 것은 잠재적으로 크리티컬한 문제를 만들 수 있다.

예를 들어, 기존 내용이 완전히 삭제된 후에 밑바닥부터 다시 내용이 쓰여지는 것과 같기 때문에, 만약 해당 HTML 구조에 이미지나 동영상과 같은 리소스가 있었다면 이들에 대한 로딩이 다시 처음부터 요구된다. 따라서 어떤 elem에 이미 수많은 이미지와 텍스트가 있었다면 이 같은 방법을 사용하여 업데이트 할 때 버벅임이 생길 수 있다.

그 외에도 innerHTML += ... 는 여러 부작용이 있다. 기존에 있던 텍스트를 마우스로 드래그한 상황에서 다시 쓰게 되면 당연히 드래그가 풀리게 될 것이고, <input> 태그에서 사용자가 입력한 값이 단번에 사라질 수도 있다.

5) outerHTML

outerHTML 프로퍼티에는 요소 전체 HTML이 담겨있다. outerHTMLinnerHTML에 요소 자체를 더한 것이라고 생각할 수 있다.

<div id="elem">Hello <b>World</b></div>

<script>
  alert(elem.outerHTML); // <div id="elem">Hello <b>World</b></div>
</script>

그러나 outerHTMLinnerHTML과는 달리 HTML 요소를 쓸땐 요소 자체가 바뀌는 방식이 아니다. 대신 outerHTMLDOM 안의 요소를 교체하는 방식을 취한다.

<div>Hello, world!</div>

<script>
  let div = document.querySelector('div');

  // div.outerHTML를 사용해 <p>...</p>로 교체
  div.outerHTML = '<p>새로운 요소</p>'; // (*)

  // div는 기존과 그대로 동일하다!
  alert(div.outerHTML); // <div>Hello, world!</div> (**)
</script>

해당 예시를 실행하면 브라우저 화면상에서는 기존 div 태그가 p 태그로 바뀌는 것을 개발자 도구 등을 통해 확인할 수있다. 그렇지만 여전히 처음에 선언된 변수 div는 이전에 저장된 값을 가지고 있다. 이런 결과가 나타나는 이유가 바로 outerHTML에 하는 할당 연산이 DOM 요소를 수정하지 않았기 때문이다. 그저 기존 요소를 DOM에서 제거하고 새로운 HTML 조각을 넣게 된다. 따라서 div.outerHTML은 다음과 같은 순서로 동작한다.

  1. 문서에서 div 제거
  2. 새로운 HTML 조각을 받아 제거된 공간에 삽입
  3. 따라서 기존 변수 div엔 여전히 기존 값이 저장된 상태이며 새로운 HTML 조각은 어디에도 저장되지 않음

정리하자면 div.innerHTMLdiv 자체를 수정하지만 div.outerHTMLdiv를 수정하지 않는다. 그렇기 때문에 elem.outerHTML에 무언가를 쓸 때는 elem 자체는 수정되지 않는다는 점을 주의해야 한다.

6) nodeValue/data로 텍스트 노드 내용 조작

innerHTML 프로퍼티는 요소 노드에만 사용할 수 있다. 만약 텍스트 노드 같은 다른 타입 노드에도 이와 유사한 기능을 수행하려먼 관련 프로퍼티인 nodeValuedata를 사용할 수 있다. 이 두 프로퍼티는 명세서 상에 미세한 차이가 존재하기는 하지만 아주 미세하기 때문에 거의 동일하다고 볼 수 있다. data 프로퍼티가 좀 더 짧기 때문에 data를 사용해서 기능을 살펴보자.

<body>
  안녕하세요.
  <!-- 주석 -->
  <script>
    let text = document.body.firstChild;
    alert(text.data); // 안녕하세요. (텍스트노드)

    let comment = text.nextSibling;
    alert(comment.data); // 주석노드
  </script>
</body>

텍스트 노드야 그 값이 문자열이고 이를 갱신하거나 접근하는 경우가 종종 일어날 것 같기에 넘어가지만, 주석 노드의 값에 접근과 수정이 왜 필요한 지 의문이 들 수 있다. 예전에는 주석을 이용하여 분기문 관련 처리를 해주는 방법을 사용하곤 했다.

<!-- if isAdmin -->
  <div>관리자로 로그인하였습니다!</div>
<!-- /if -->

위와 같은구조에서 data 프로퍼티를 통해 주석 노드의 내용을 읽고 조건에 부합하는 로직을 처리한 후 다음으로 넘어가는 등의 작업을 해 줄 수 있다.

7) textContent 순수한 텍스트

textContent를 사용하면 요소 내 텍스트에 접근이 가능하다. 이때 태그 요소는 완전히 배제하고 오직 순수 텍스트만 추출이 가능하다.

<div id="news">
  <h1>주요 뉴스!</h1>
  <p>화성인이 지구를 침공!</p>
</div>

<script>
  // 주요 뉴스! 화성인이 지구를 침공!
  alert(news.textContent);
</script>

위의 예시를 보면 id="newsdiv 태그에서 오직 텍스트에만 해당하는 내용이 출력되는 것을 확인할 수 있다. 이처럼 textContent를 사용하면 텍스트를 안전한 방법으로 쓸 수 있기 때문에 쓰기 용으로 유용하게 사용할 수 있다. 즉 사용자의 입력값을 받아서 처리할 때 태그와 같은 요소를 무시하게끔 설정하려면 textContent를 이용할 수 있다.

8) hidden 프로퍼티

hidden 속성과 hidden 프로퍼티는 요소를 보여줄 지 말지 지정할 때 사용할 수 있다. 이 값을 설정하는 것은 CSS에서 display: none을 적용한 것과 동일한 기능을 수행한다. hidden은 HTML 태그 속성으로도 존재하고, 자바스크립트 객체의 프로퍼티로도 존재하기 때문에 HTML과 자바스크릅티에서 모두 사용 가능하다.

<div>아래 두 div를 숨김처리</div>

<div hidden>HTML의 hidden 속성 사용</div>

<div id="elem">자바스크립트의 hidden 프로퍼티 사용</div>

<script>
  elem.hidden = true;
</script>

9) 기타 프로퍼티

지금까지 소개한 프로퍼티 외에도 DOM 요소에는 다양한 프로퍼티가 존재한다. 클래스마다 특징적인 몇 가지 프로퍼티를 소개하면 다음과 같다.

  • value : <input>/<select>/<textarea> 에서 입력하는 값이 저장되는 프로퍼티 (HTMLInputElement/HTMLSelectElement)
  • href : <a href='...'> 에서 href의 속성 값이 저장되는 프로퍼티 (HTMLAnchorElement)
  • id : id 속성 값이 저장되는 프로퍼티. 모든 요소 노드에서 사용 가능 (HTMLElement)
  • ...

대부분의 표준 HTML 속성은 그에 대응하는 DOM 프로퍼티를 가지고 있는데 위 예시와 같은 방식으로 프로퍼티에 접근할 수 있는 경우가 많다. 특정 클래스에서 지원하는 프로퍼티 여부에 대한 전체 사항을 확인하고 싶다면 명세서를 참고하거나, 개발자 도구의 콘솔창에서 console.dir(elem) 또는 개발자 도구의 Elements 패널 하위 패널에서 Properties 탭에서 목록을 확인할 수 있다.

그러나 이처럼 HTML의 요소 속성과 DOM 노드의 프로퍼티가 항상 동일한 것은 아니다. 이와 관련된 내용은 다음 챕터에서 계속 살펴보자.

References

  1. https://ko.javascript.info/document
  2. https://dom.spec.whatwg.org/#node
  3. https://html.spec.whatwg.org/#htmlinputelement
profile
개발잘하고싶다

0개의 댓글