Skip to content

Commit

Permalink
Merge pull request #1225 from e6d1fe/e6d1fe
Browse files Browse the repository at this point in the history
39-3μž₯ DOM - λ‚˜μ„Έν˜„
  • Loading branch information
Ryan-Dia authored Jan 18, 2024
2 parents dd997ca + b42328b commit a7f9589
Showing 1 changed file with 132 additions and 0 deletions.
132 changes: 132 additions & 0 deletions docs/39_DOM/λ‚˜μ„Έν˜„.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,135 @@ HTML μš”μ†Œμ— `id` μ–΄νŠΈλ¦¬λ·°νŠΈλ₯Ό λΆ€μ—¬ν•˜λ©΄ `id` κ°’κ³Ό λ™μΌν•œ 이름
`getElementsByClassName` λ©”μ„œλ“œλŠ” 인수둜 μ „λ‹¬ν•œ `class` 값을 κ°–λŠ” λͺ¨λ“  μš”μ†Œ λ…Έλ“œλ“€μ„ 탐색해 λ°˜ν™˜ν•œλ‹€.
`getElementsByTagName` λ©”μ„œλ“œμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ HTMLCollection 객체λ₯Ό λ°˜ν™˜ν•˜λ©°, `Document.prototype`와 `Element.prototype`에 μ •μ˜λœ λ©”μ„œλ“œκ°€ μžˆλ‹€.
인수둜 μ „λ‹¬λœ `class` 값을 κ°–λŠ” μš”μ†Œκ°€ μ—†λ‹€λ©΄ 빈 HTMLCollection 객체λ₯Ό λ°˜ν™˜ν•œλ‹€.

#### CSS μ„ νƒμžλ₯Ό μ΄μš©ν•œ μš”μ†Œ λ…Έλ“œ 취득

- `* { ... }`: 전체 μ„ νƒμž (λͺ¨λ“  μš”μ†Œλ₯Ό 선택)
- `p { ... }`: νƒœκ·Έ μ„ νƒμž (λͺ¨λ“  p νƒœκ·Έ μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `#foo { ... }`: id μ„ νƒμž (id 값이 'foo'인 μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `.foo { ... }`: class μ„ νƒμž (class 값이 'foo'인 μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `input[type=text] { ... }`: μ–΄νŠΈλ¦¬λ·°νŠΈ μ„ νƒμž (input μš”μ†Œ 쀑에 type μ–΄νŠΈλ¦¬λ·°νŠΈ 값이 'text'인 μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `div p { ... }`: 후손 μ„ νƒμž (div μš”μ†Œμ˜ 후손 μš”μ†Œ 쀑 p μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `div > p { ... }`: μžμ‹ μ„ νƒμž (div μš”μ†Œμ˜ μžμ‹ μš”μ†Œ 쀑 p μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `p + ul { ... }`: 인접 ν˜•μ œ μ„ νƒμž (p μš”μ†Œμ˜ ν˜•μ œ μš”μ†Œ 쀑에 p μš”μ†Œ λ°”λ‘œ 뒀에 μœ„μΉ˜ν•˜λŠ” ul μš”μ†Œλ₯Ό 선택)
- `p ~ ul { ... }`: 일반 ν˜•μ œ μ„ νƒμž (p μš”μ†Œμ˜ ν˜•μ œ μš”μ†Œ 쀑에 p μš”μ†Œ 뒀에 μœ„μΉ˜ν•˜λŠ” ul μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `a: hover { ... }`: 가상 클래슀 μ„ νƒμž (hover μƒνƒœμΈ a μš”μ†Œλ₯Ό λͺ¨λ‘ 선택)
- `p::before { ... }`: 가상 μš”μ†Œ μ„ νƒμž (p μš”μ†Œμ˜ μ½˜ν…μΈ μ˜ μ•žμ— μœ„μΉ˜ν•˜λŠ” 곡간을 선택, 일반적으둜 content ν”„λ‘œνΌν‹°μ™€ ν•¨κ»˜ μ‚¬μš©λ¨)

`querySelector` λ©”μ„œλ“œλŠ” 인수둜 μ „λ‹¬ν•œ CSS μ„ νƒμžλ₯Ό λ§Œμ‘±μ‹œν‚€λŠ” ν•˜λ‚˜μ˜ μš”μ†Œ λ…Έλ“œλ₯Ό 탐색해 λ°˜ν™˜ν•œλ‹€.
μ—¬λŸ¬ κ°œκ°€ μžˆμ„ 경우 첫번째만 λ°˜ν™˜ν•˜λ©°, 인수둜 μ „λ‹¬ν•œ μ„ νƒμžλ₯Ό λ§Œμ‘±μ‹œν‚€λŠ” μš”μ†Œ λ…Έλ“œκ°€ μ—†λŠ” 경우 `null`을 λ°˜ν™˜ν•œλ‹€.

`querySelectorAll` λ©”μ„œλ“œλŠ” 인수둜 μ „λ‹¬ν•œ CSS μ„ νƒμžλ₯Ό λ§Œμ‘±μ‹œν‚€λŠ” λͺ¨λ“  μš”μ†Œ λ…Έλ“œλ₯Ό 탐색해 λ°˜ν™˜ν•œλ‹€.
μ—¬λŸ¬ 개의 μš”μ†Œ λ…Έλ“œ 객체λ₯Ό κ°–λŠ” DOM μ»¬λ ‰μ…˜ 객체인 NodeList 객체λ₯Ό λ°˜ν™˜ν•˜λ©° μ΄λŠ” μœ μ‚¬ λ°°μ—΄ κ°μ²΄μ΄λ©΄μ„œ μ΄ν„°λŸ¬λΈ”μ΄λ‹€.

`getElementsByTagName`, `getElementsByClassName` λ©”μ„œλ“œμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ `querySelector`, `querySelectorAll` λ©”μ„œλ“œλŠ” `Document.prototype`에 μ •μ˜λœ λ©”μ„œλ“œμ™€ `Element.prototype`에 μ •μ˜λœ λ©”μ„œλ“œκ°€ μžˆλ‹€.

#### νŠΉμ • μš”μ†Œ λ…Έλ“œλ₯Ό 취득할 수 μžˆλŠ”μ§€ 확인

`Element.prototype.matches` λ©”μ„œλ“œλŠ” 인수둜 μ „λ‹¬ν•œ CSS μ„ νƒμžλ₯Ό 톡해 νŠΉμ • μš”μ†Œλ₯Ό 취득할 수 μžˆλŠ”μ§€ ν™•μΈν•œλ‹€.

```html
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li class="apple">apple</li>
<li class="banana">banana</li>
<li class="orange">orange</li>
</ul>
<script>
const apple = document.querySelector('.apple');
console.log(apple.matches('#fruits > li.apple')); // true
console.log(apple.matches('#fruits > li.banana')); // false
</script>
</body>
</html>
```

#### `HTMLCollection`κ³Ό `NodeList`

DOM μ»¬λ ‰μ…˜ 객체인 `HTMLCollection`κ³Ό `NodeList`λŠ” DOM APIκ°€ μ—¬λŸ¬ 개의 결과값을 λ°˜ν™˜ν•˜κΈ° μœ„ν•œ DOM μ»¬λ ‰μ…˜ 객체닀.
λ‘˜ λ‹€ μœ μ‚¬ λ°°μ—΄ κ°μ²΄μ΄λ©΄μ„œ μ΄ν„°λŸ¬λΈ”μ΄λ―€λ‘œ `for ... of` 문으둜 μˆœνšŒν•  수 있으며 μŠ€ν”„λ ˆλ“œ 문법을 μ‚¬μš©ν•΄ κ°„λ‹¨νžˆ λ°°μ—΄λ‘œ λ³€ν™˜ν•  수 μžˆλ‹€.
**두 객체의 μ€‘μš”ν•œ νŠΉμ§•μ€ λ…Έλ“œ 객체의 μƒνƒœ λ³€ν™”λ₯Ό μ‹€μ‹œκ°„μœΌλ‘œ λ°˜μ˜ν•˜λŠ” μ‚΄μ•„ μžˆλŠ” κ°μ²΄λΌλŠ” 것이닀.**
`HTMLCollection`은 μ–Έμ œλ‚˜ live 객체둜 λ™μž‘ν•œλ‹€.
`NodeList`λŠ” λŒ€λΆ€λΆ„μ˜ 경우 non-live 객체둜 λ™μž‘ν•˜μ§€λ§Œ κ²½μš°μ— 따라 live 객체둜 λ™μž‘ν•  λ•Œκ°€ μžˆλ‹€.

`getElementsByTagName`, `getElementsByClassName` λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•˜λŠ” `HTMLCollection` κ°μ²΄λŠ” λ…Έλ“œ 객체의 μƒνƒœ λ³€ν™”λ₯Ό μ‹€μ‹œκ°„μœΌλ‘œ λ°˜μ˜ν•˜λŠ” μ‚΄μ•„ μžˆλŠ” DOM μ»¬λ ‰μ…˜ 객체닀.

```html
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li class="red">apple</li>
<li class="red">banana</li>
<li class="red">orange</li>
</ul>
<script>
const elems = document.getElementsByClassName('red');
console.log(elems); // HTMLCollection(3) [li.red, li.red, li.red]
for (let i = 0; i < elems.length; i++) {
elems[i].className = 'blue';
}
console.log(elems); // HTMLCollection(1_ [li.red])
</script>
</body>
</html>
```

μœ„ 예제의 κ²°κ³Ό λͺ¨λ“  `li` μš”μ†Œμ˜ `class` 값이 `blue`둜 λ³€κ²½λ˜μ–΄μ•Ό ν•  것 κ°™μ§€λ§Œ, μ˜ˆμƒλŒ€λ‘œ λ™μž‘ν•˜μ§€ μ•ŠλŠ”λ‹€.

1. 첫번째 반볡(`i === 0`): `elems[0]`의 `class` 값이 `red`μ—μ„œ `blue`둜 λ³€κ²½λœλ‹€. μ΄λ•Œ 이 μš”μ†ŒλŠ” `getElementsByClassName`의 인자둜 μ „λ‹¬ν•œ `red`와 μΌμΉ˜ν•˜μ§€ μ•Šκ²Œ 되기 λ•Œλ¬Έμ— `elems`μ—μ„œ μ‹€μ‹œκ°„μœΌλ‘œ μ œκ±°λœλ‹€.
2. λ‘λ²ˆμ§Έ 반볡(`i === 1`): 첫번째 λ°˜λ³΅μ—μ„œ 첫번째 `li` μš”μ†ŒλŠ” `elems`μ—μ„œ μ œκ±°λ˜μ—ˆμœΌλ―€λ‘œ `elems[1]`은 μ„Έλ²ˆμ§Έ `li` μš”μ†Œλ‹€. 이 μ„Έλ²ˆμ§Έ μš”μ†Œμ˜ `class` 값도 `blue`둜 λ³€κ²½λœ ν›„ μ‹€μ‹œκ°„μœΌλ‘œ μ œμ™Έλœλ‹€.
3. μ„Έλ²ˆμ§Έ 반볡(`i === 2`): `elems`μ—λŠ” λ‘λ²ˆμ§Έ `li` μš”μ†Œλ§Œ 남아 μžˆλ‹€. μ΄λ•Œ `elems.length`의 값은 `1`μ΄λ―€λ‘œ `for`문의 쑰건식 `i < elems.length`κ°€ κ±°μ§“μœΌλ‘œ ν‰κ°€λ˜μ–΄ 반볡이 μ’…λ£Œλœλ‹€.

이처럼 `HTMLCollection` κ°μ²΄λŠ” μ‹€μ‹œκ°„μœΌλ‘œ μƒνƒœ 변경을 λ°˜μ˜ν•˜λ―€λ‘œ 이λ₯Ό `for`문으둜 μˆœνšŒν•˜λ©΄μ„œ λ…Έλ“œ 객체의 μƒνƒœλ₯Ό λ³€κ²½ν•  λ•Œ μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.
이 λ¬Έμ œλŠ” λ‹€μŒκ³Ό 같은 λ°©λ²•μœΌλ‘œ ν•΄κ²°ν•  수 μžˆλ‹€.

```javascript
// for문을 μ—­λ°©ν–₯으둜 순회
for (let i = elems.length - 1; i >= 0; i--) {
elems[i].className = 'blue';
}

// while문으둜 HTMLCollection에 μš”μ†Œκ°€ 남아 μžˆμ§€ μ•Šμ„ λ•ŒκΉŒμ§€ λ¬΄ν•œ 반볡
let i = 0;
while (elems.length > i) {
elems[i].className = 'blue';
}

// 더 κ°„λ‹¨ν•œ ν•΄κ²°μ±…: λΆ€μž‘μš©μ„ λ°œμƒμ‹œν‚€λŠ” 원인인 HTMLCollection 객체λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠκΈ°
[...elems].forEach((elem) => (elem.className = 'blue'));
```

`HTMLCollection` 객체의 λΆ€μž‘μš©μ„ ν•΄κ²°ν•˜κΈ° μœ„ν•΄ `getElementsByTagName`, `getElementsByClassName` λŒ€μ‹  `querySelectorAll` λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 방법도 μžˆλ‹€.
이 λ©”μ„œλ“œλŠ” DOM μ»¬λ ‰μ…˜ 객체인 `NodeList` 객체λ₯Ό λ°˜ν™˜ν•˜λ©°, μ΄λŠ” μ‹€μ‹œκ°„μœΌλ‘œ λ…Έλ“œ 객체의 μƒνƒœ 변경을 λ°˜μ˜ν•˜μ§€ μ•ŠλŠ” 객체닀.
`NodeList` κ°μ²΄λŠ” `NodeList.prototype.forEach` λ©”μ„œλ“œλ₯Ό 상속받아 μ‚¬μš©ν•  수 μžˆλ‹€.
ν•˜μ§€λ§Œ **`childNodes` ν”„λ‘œνΌν‹°κ°€ λ°˜ν™˜ν•˜λŠ” `NodeList` κ°μ²΄λŠ” `HTMLCollection` 객체와 같이 live 객체둜 λ™μž‘ν•˜λ―€λ‘œ μ£Όμ˜κ°€ ν•„μš”ν•˜λ‹€.**

이처럼 `HTMLCollection`μ΄λ‚˜ `NodeList`λŠ” μ˜ˆμƒκ³Ό λ‹€λ₯΄κ²Œ λ™μž‘ν•  λ•Œκ°€ 있기 λ•Œλ¬Έμ— λ…Έλ“œ 객체의 μƒνƒœ λ³€κ²½κ³Ό 상관없이 μ•ˆμ „ν•˜κ²Œ λ°°μ—΄λ‘œ λ³€ν™˜ν•œ ν›„ μ‚¬μš©ν•˜λŠ” 것을 ꢌμž₯ν•œλ‹€.

```html
<!DOCTYPE html>
<html>
<body>
<ul id="fruits">
<li>apple</li>
<li>banana</li>
</ul>
<script>
const fruits = document.getElementById('fruits');
const { childNodes } = fruits;
[...childNodes].forEach((childNode) => fruits.removeChild(childNode));
console.log(childNodes); // NodeList []
</script>
</body>
</html>
```

0 comments on commit a7f9589

Please sign in to comment.