Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

39-3장 DOM - 고세종 #1226

Merged
merged 1 commit into from
Jan 18, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions docs/39_DOM/고세종.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,95 @@ document 객체는 브라우저가 렌더링한 HTML 문서 전체를 가르키

DOM은 HTML 문서의 계층적 구조와 정보를 표현하는 것은 물론 노드 객체의 종류, 즉 노드 타입에 따라 필요한 기능을 프로퍼티와 메서드의 집합인 DOM API로 제공한다.<br>
이 DOM API를 통해 HTML의 구조나 내용 또는 스타일 등을 동적으로 조작할 수 있다.

---

## 요소 노드 취득

우선 자바스크립트 등을 이용해 HTML을 동적으로 조작하기 위해선 요소 노드를 취득해야 한다.

노드에 접근하는 방법에 대해서 알아보자.

### id를 이용한 요소 노드 취득

`Document.prototpye.getElementById` 메서드는 인수로 전달한 id 어트리뷰트 값을 갖는 하나의 요소 노드를 반환한다.

```html
<div id="something">I'm div</div>
<script>
console.log(document.getElementById('something')); // <div id="something">something</div>
</script>
```

id 값은 HTML 문서 내에서 유일한 값이어야 하며, class 어트리뷰트와는 달리 공백 문자로 구분하여 여러개의 값을 가질 수 없다.<br>
만약 같은 id값으 갖는 요소들이 여러개라도 `getElementById` 메서드는 첫 번째 요소 노드만 반환한다.

HTML 요소에 id 속성을 부여하면 id 값과 동일한 이름의 전역 변수가 암묵적으로 선언되고 해당 노드 객체가 할당되는 부수 효과가 있다.

### 태그 이름을 이용한 요소 노드 취득

`Document.prototype/Element.prototype.getElementsByTagName` 메서드는 인수로 전달한 태그 이름을 갖는 모든 요소들을 반환한다.<br> 이때 반환된 값은 DOM 컬렉션 객체인 `HTMLCollection` 객체를 반환한다.

> HTMLCollection 객체는 유사 배열 객체이면서 이터러블이다.

### class를 이용한 요소 노드 취득

`Document.prototype/Element.prototype.getElementsByClassName` 메서드는 인수로 전달한 class 어트리뷰트 값을 갖는 모든 요소 노드들을 반환한다.<br>
인수로 전달할 class값은 공백으로 구분하여 여러개의 class를 지정할 수 있다.

### CSS 선택자를 이용한 요소 노드 취득

CSS 선택자는 스타일을 적용하고자 하는 HTML 요소를 특정할 때 사용하는 문법이다.

`Document.prototype/Element.prototype.querySelector` 메서드는 인수로 전달한 CSS 선택자를 만족시키는 하나의 요소 노드를 탐색하여 반환한다.

`Document.prototype/Element.prototype.querySelectorAll` 메서드는 인수로 전달한 CSS 선택자를 만족시키는 모든 요소 노드를 D
OM 컬렉션 객체인 NodeList객체로 반환한다.

> `querySelector, querySelectorAll` 메서드는 `getElementById, getElementBy***` 메서드보다 다소 느린것으로 알려져있다.<br> id 어트리뷰트가 있는 요소 노드를 취득하는 경우에는 `getElementById` 메서드를 사용하고, 그 외에는 `querySelector, querySelectorAll` 메서드를 사용하자.

### HTMLCollection과 NodeList

HTMLCollection과 NodeList는 모두 유사 배열 객체이면서 이터러블이다.

이 두가지 객체의 중요한 특징은 노드 객체의 상태 변화를 실시간으로 반영하는 살아있는 객체라는 것이다.<br>
HTMLCollection은 언제나 live객체로 동작하는 반면 NodeList는 대부분의 경우 non-live 객체로 동작한다.

> NodeList도 경우에 따라 live 객체로 동작한다.

### HTMLCollection

`getElementsByTagNAme, getElementByClassName` 메서드가 반환하는 HTMLCollection 객체는 노드 객체의 상태 변화를 실시간으로 반영한다.

```html
<ul id="fruits">
<li class="red">apple</li>
<li class="red">banana</li>
<li class="red">orange</li>
</ul>
```

위 ul 태그중 li 태그들의 class를 전부 'blue'로 변경해보자.

```javascript
const $elmes = document.getElementsByClassName('red');
for (let i = 0; i < $elems.length; i++) {
$elems[i].className = 'blue';
}
```

위 코드의 동작 결과로 `apple, banana, orange` 3개의 li태그 모두 blue로 변경될것을 예상할 수 있지만 `banana` li태그는 변경되지 않는다.

그 이유는 HTMLCollection이 live 객체라는 점에 있다.<br>
첫번째 li태그인 `apple` 태그의 class가 blue로 변경되는 순간 $elems에는 재할당이 이루어 지며 $elems는 apple을 제외한 banana, orange 두개의 태그가 들어가고, for 문의 i는 이미 증가된 상태가 된다.

따라서, banana li 태그는 변경되지 않았기에 재할당이 이루어지지 않아 orange li 태그는 blue로 변경된다.

이런 문제를 예방하기 위해서는 배열의 고차함수를 사용하는것이 좋다.

### NodeList

HTMLCollection 객체의 부작용을 해결하기 위해 `querySelectorAll` 메서드를 사용하는 방법도 있다.<br>
NodeList는 non-live 객체이기 때문에 이런 부작용을 예방해 주지만 `childNode` 프로퍼티가 반환되는 NodeList 객체는 HTMLCollection 객체와 같이 실시간으로 노드 객체의 상태 변경을 반영하는 live 객체로 동작하므로 주의가 필요하다.

**따라서 이렇게 예상과 다른 동작을 피하고 예방하기 위해선 노드 객체의 상태 변경과 상관없이 안전하게 DOM 컬렉션을 사용하려면 HTMLCollection이나 NodeList 객체를 배열로 변환하여 사용하는 것을 권장한다.**
Loading