์ ์ฌ ๋ฐฐ์ด ๊ฐ์ฒด์ด๋ฉด์ iterableํ ์ฑ์ง์ ๊ฐ๊ณ ์์ด for...of๋ฌธ์ผ๋ก ์ํํ ์ ์์ผ๋ฉฐ ์คํ๋ ๋ ๋ฌธ๋ฒ์ ์ฌ์ฉํ๋ฉด ๊ฐ๋จํ ๋ฐฐ์ด๋ก ๋ณํํ ์๋ ์๋ค.
์ด๋ ๊ฒ ๋ฐฐ์ด๋ก ๋ณํ๋ ๊ฐ์ฒด๋ ๋ฐฐ์ด์์ ์ ๊ณตํ๋ ๊ณ ์ฐจ ํจ์(forEach, map, etc.)๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
๋
ธ๋ ๊ฐ์ฒด์ ์ํ ๋ณํ๋ฅผ ์ค์๊ฐ์ผ๋ก ๋ฐ์ํ live ๊ฐ์ฒด์ด๋ค. HTML Collection์ ์ธ์ ๋ live ๊ฐ์ฒด๋ก ๋์
ํ๋ค. ์ด๋ฌํ ํน์ฑ์ผ๋ก ๊ฐ์ฒด๋ฅผ for๋ฌธ์ผ๋ก ์ํํ์ฌ ๋
ธ๋ ๊ฐ์ฒด์ ์ํ๋ฅผ ๋ณ๊ฒฝํด์ผ ํ ๊ฒฝ์ฐ์ ์ฃผ์๋ฅผ ์ํ๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํํผํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
HTMLCollection์ ๋ฐฐ์ด๋ก ๋ณํํ์ฌ ์ํ โญ๏ธ
<script>
const $elem = document.getElementsByClassName("red");
// class๊ฐ 'red'์ธ HTMLCollection ๊ฐ์ฒด์ ๋ชจ๋ ์์์ class ๊ฐ์ 'blue'๋ก ๋ณ๊ฒฝํด๋ผ.
[...$elem].forEach(elem => elem.className = "blue");
// class๊ฐ "red"์ธ HTMLCollection ๊ฐ์ฒด์ ๋ชจ๋ ์์์ class ๊ฐ์ "green"์ผ๋ก ๋ณ๊ฒฝํด๋ผ.
Array.from($elem).forEach(elem => elem.className = "green");
</script>
NodeList๋ ๋๋ถ๋ถ non-live ๊ฐ์ฒด๋ก ๋์
ํ๋ค. ๋ค๋ง, childNodes ํ๋กํผํฐ๊ฐ ๋ฐํํ๋ NodeList ๊ฐ์ฒด๋ live ๊ฐ์ฒด๋ก ๋์ํ๋ฏ๋ก ์ฃผ์๊ฐ ํ์
ํ๋ค. ๋ฐ๋ผ์ ๋
ธ๋ ๊ฐ์ฒด ํ์
๊ณผ ์๊ด์์ด ๋ฐฐ์ด๋ก ๋ณํํ์ฌ ์ํํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<ul id="fruits">
<li>Apple</li>
<li>Banana</li>
<li>Grape</li>
</ul>
<ul>
<li>html</li>
</ul>
<script>
const $fruits = document.getElementById("fruits");
const $listFromFruits = $fruits.getElementsByTagName("li");
// childNodes ํ๋กํผํฐ๊ฐ ๋ฐํํ NodeList ๊ฐ์ฒด
console.log($fruits.childNodes);
// NodeList(7) [text, li, text, li, text, li, text]
</script>
</body>
</html>
๋
ธ๋ ํ์ ํ๋กํผํฐ
๋ ๋ชจ๋ ์ ๊ทผ์ ํ๋กํผํฐ๋ก setter์์ด getter๋ง ์กด์ฌํ๋ ์ฝ๊ธฐ ์ ์ฉ ํ๋กํผํฐ
์ด๋ค. ์ฝ๊ธฐ ์ ์ฉ ํ๋กํผํฐ์ ๊ฐ์ ํ ๋นํ ๊ฒฝ์ฐ ์๋ฌ ์์ด ๋ฌด์๋๋ค.
Q. ๋ธ๋ผ์ฐ์ ์ฝ์์ฐฝ์ Node.prototype, Element.prototype์ ์ ๋ ฅํ์ฌ ์ฝ๊ธฐ ์ ์ฉ ํ๋กํผํฐ๋ฅผ ํ์ธํด๋ณด์.
Node.prototype.childNodes
: ์์ ๋
ธ๋๋ฅผ ๋ชจ๋ ํ์ํ์ฌ NodeList์ ๋ด์ ๋ฐํํ๋ค. ๋ฐํ๋ ๋ฆฌ์คํธ์๋ ํ
์คํธ ๋
ธ๋๋ ํฌํจ๋์ด ์์ ์ ์๋ค.
Element.prototyle.children
: ์์ ๋
ธ๋๋ฅผ ํ์ํ์ฌ ์์ ๋
ธ๋๋ง HTMLCollection์ ๋ด์ ๋ฐํํ๋ค. ๋ฐํ๋ ๋ฆฌ์คํธ์๋ ํ
์คํธ ๋
ธ๋๋ ํฌํจ๋์ง ์๋๋ค.
nodeValue
: ํ
์คํธ ๋
ธ๋
์ Node.prototype.nodeValue๋ฅผ ์ฌ์ฉํ๋ฉด ๋
ธ๋ ๊ฐ์ฒด์ ๊ฐ, ํ
์คํธ๋ฅผ ๋ฐํ
ํ๋ค. ํ
์คํธ ๋
ธ๋๊ฐ ์๋ ๊ฒฝ์ฐ์ ์ฌ์ฉํ ๊ฒฝ์ฐ์๋ null์ ๋ฐํํ๋ค.
textContent
: ์์ ๋
ธ๋
์ Node.prototype.textContent๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, ์์ ๋
ธ๋์ ๋ชจ๋ ์์ ๋
ธ๋์ ํ
์คํธ๋ฅผ ๋ชจ๋ ์ทจ๋ํ์ฌ ๋ฐํ
ํ๋ค. ์ด ๋, HTML ๋งํฌ์
์ ๋ฌด์๋๋ค.
innerText
: textContent์ ์ ์ฌํ๊ฒ ๋์ํ์ง๋ง CSS์ ์์ข
์
์ด๋ค. ์ฆ, CSS ์คํ์ผ๋ก ๋นํ์๋ก ์ง์ : visibility: hidden;๋ ์์ ๋
ธ๋์ ์ฌ์ฉํ ๊ฒฝ์ฐ์ ๋
ธ๋์ ํ
์คํธ๋ฅผ ๋ฐํํ์ง ๋ชปํ๊ณ CSS๋ฅผ ๊ณ ๋ คํด์ผํด์ ์กฐ์์ด ๋๋ฆฌ๋ค๋ ๋จ์
์ด ์์ด ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข๋ค.
innerHTML
: ์์ ๋
ธ๋์ innerHTML ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ํด๋น ์์ ๋
ธ๋ ์ฌ์ด์ ์๋ ๋ชจ๋ HTML ๋งํฌ์
์ ๋ฌธ์์ด๋ก ๋ฐํํ๋ค. ํด๋น ํ๋กํผํฐ๋ฅผ ํตํด์ HTML ๋งํฌ์
์ด ํฌํจ๋ ๋ด์ฉ์ ์ฌํ ๋นํ ๊ฒฝ์ฐ, HTML์ ํ์ฑ๋์ด ๋ด์ฉ์ด ์ ์ฉ๋๋ค.
์ฌ์ฉ์๋ก๋ถํฐ ๋ฐ์ ์ ๋ณด๋ฅผ innerHTML์ ์ด์ฉํด์ ๋ณ๊ฒฝํ ๊ฒฝ์ฐ, ํฌ๋ก์ค ์ฌ์ดํธ ์คํฌ๋ฆฝํ
๊ณต๊ฒฉ(XSS)์ ์ทจ์ฝ
ํ์ฌ ์ํํ๋ค. ๋ฐ๋ผ์ ๋ณ๊ฒฝ์ฌํญ์ ๋ฐ๋ก ์ ์ฉํ๋ ๊ฒ์ด ์๋๋ผ HTML sanization(์ด๊ท ) ๊ณผ์ ์ ๊ฑฐ์น๊ณ ์์ ์ฑ์ด ๋ณด์ฅ๋ ๋ด์ฉ์ ์ ์ฉํ๋ ๊ฒ์ ๊ถ์ฅ
ํ๋ค. (์ฐธ์กฐ: DOM Purify)
๊ธฐ์กด์ ์์๋ฅผ ๋ณ๊ฒฝํ์ง ์์ผ๋ฉด์ ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ ค๊ณ ํ ๊ฒฝ์ฐ, DOM ์กฐ์์ ๋ณ๊ฒฝํ ์์น๋ฅผ ํน์ ํ ์ ์์ด ์์ ๋ ธ๋ ์ฌ์ด์ ์๋ ๋ชจ๋ ๋ ธ๋๋ฅผ ์ ๊ฑฐํ๊ณ ๊ธฐ์กด ๋ ธ๋ + ์๋ก์ด ๋ ธ๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค๋ ๋จ์ ์ด ์๋ค.
isertAdjacentHTML(position, DOMString)
: innerHTML๊ณผ ๋ค๋ฅด๊ฒ ์๋กญ๊ฒ ์ฝ์
ํ ์์(DOMString)์ ์ฝ์
์์น(position)๋ฅผ ์ง์ ํ ์ ์์ด ๋น ๋ฅด๋ค๋ ์ฅ์ ์ด ์๋ค. ๋ค๋ง XSS ๊ณต๊ฒฉ์๋ ์ฌ์ ํ ์ทจ์ฝํ๋ค.
<!-- beforebegin -->
<p>
<!-- afterbegin -->
foo
<!-- beforeend -->
</p>
<!-- afterend -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<ul id="fruits">
<li>Apple</li>
</ul>
<script>
const $fruits = document.getElementById("fruits");
// ์์ ๋
ธ๋ ์์ฑ : ํ๋ก ์กด์ฌํ๋ ์ํ
const $li = document.createElement("li");
// ํ
์คํธ ๋
ธ๋ ์์ฑ: ํ๋ก ์กด์ฌํ๋ ์ํ
const $textNode = document.createTextNode("Banana");
// ์์ ๋
ธ๋์ ํ
์คํธ ๋
ธ๋๋ฅผ ๋ง์ง๋ง ์์์ผ๋ก ์ถ๊ฐ
// ์์ ๋
ธ๋์ ์์ ๋
ธ๋๊ฐ ์๋ ๊ฒฝ์ฐ, ํ
์คํธ ๋
ธ๋๋ฅผ ์์ฑํ๋ ๊ณผ์ ์์ด
// $li.textContent = "Banana";๋ก ๋์ฒด ๊ฐ๋ฅํ๋ค.
$li.appendChild($textNode);
// $fruits ์์น์ ์๋ก ์์ฑํ $li๋ฅผ ๋ง์ง๋ง ์์ ๋
ธ๋๋ก ์ถ๊ฐ
$fruits.appendChild($li);
</script>
</body>
</html>
๋
ธ๋์ ์์ฑ๊ณผ ์ถ๊ฐ ๊ณผ์ ์์ ๋ณต์๊ฐ์ ๋
ธ๋๋ฅผ ์์ฑํ์ฌ ์ถ๊ฐ
ํด์ผ ํ ๊ฒฝ์ฐ, ๋
ธ๋๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค ๋ฆฌํ๋ก์ฐ์ ๋ฆฌํ์ธํธ๊ฐ ์ผ์ด๋ ์ฑ๋ฅ์ ์ผ๋ก ์ข์ง ๋ชปํ๊ณ ๋นํจ์จ์
์ด๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํํผํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
์ปจํ ์ด๋ ์์๋ฅผ ๋ณ๋๋ก ์์ฑํด์ ์์์ ์์์ผ๋ก ์ถ๊ฐ๋ ๋ ธ๋๋ฅผ ๋จผ์ ์ถ๊ฐํ๊ณ ๋ฐ๋ณต ์์ ์ด ๋๋๋ฉด ์ค์ ์ฝ์ ํ ์์น์ ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ํ์ง๋ง ๋ถํ์ํ ์ปจํ ์ด๋ ์์๊ฐ DOM์ ์ถ๊ฐ๋๋ ๋ถ์์ฉ์ด ์๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ DocumentFragment ๋
ธ๋
๊ฐ ํด๊ฒฐํ ์ ์๋ค. DOM์ ์ถ๊ฐํ ๋ณต์๊ฐ์ ์์๋
ธ๋๋ฅผ ์์ฑํ ๋ค fragment ๋
ธ๋์ ์์ ๋
ธ๋๋ก ์ถ๊ฐํ๊ณ fragment ๋
ธ๋๋ฅผ DOM์ ์ถ๊ฐํ๋ฉด ์์ ์ ์ ๊ฑฐ๋๊ณ ์์ฑ๋ ์์๋
ธ๋๋ง DOM์ ์ถ๊ฐ
๋๋ค.
insertBefore(newNode, childNode)
: ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ๋
ธ๋๋ฅผ ๋ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ๋
ธ๋ ์์ ์ฝ์
ํ๋ค. appendChild์ ๋ค๋ฅด๊ฒ ์ฝ์
์์น๋ฅผ ์ง์ ํ ์ ์๋ค.
๋ ๋ฒ์งธ ์ธ์๊ฐ ์์ ๋ ธ๋๊ฐ ์๋ ๊ฒฝ์ฐ: DOM Exception error ๋ฐ์
๋ ๋ฒ์งธ ์ธ์๊ฐ null์ธ ๊ฒฝ์ฐ: appendChild์ ๋์ผํ๊ฒ ๋์
๋์ ์ด๋ฏธ ์กด์ฌํ๋ ์์ ๋ ธ๋๋ฅผ ์ทจ๋ํ ๋ค appendChild ํน์ insertBefore๋ฅผ ์ฌ์ฉํ๋ฉด ๊ธฐ์กด ๋ ธ๋๋ฅผ ์ ๊ฑฐํ๊ณ ์๋ก์ด ์์น์ ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ค. ์ฆ ๋ ธ๋ ์ด๋์ด ๋ฐ์ํ๋ค.
Node.prototype.cloneNode([deep: true | false])๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ธ๋์ ์ฌ๋ณธ์ ์์ฑํ์ฌ ๋ฐํํ๋ค. deep์ true๋ฅผ ์ ๋ฌํ๋ฉด ์์ ๋ ธ๋๊น์ง ํฌํจํ ๊น์ ๋ณต์ฌ๋ฅผ false๋ฅผ ์ ๋ฌํ๋ฉด ์๊ธฐ ์์ ๋ง์ ์๊ฒ ๋ณต์ฌํ๋ค. ์์ ๋ณต์ฌ๋ฅผ ํตํด ์ด๋ค์ง ๋ณต์ฌ๋ ์์ ๋ ธ๋๋ฅผ ๋ณต์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ ํ ์คํธ ๋ ธ๋์กฐ์ฐจ ์๋ค.
Node.prototype.replaceChild(newChild, oldChild) ๋ฉ์๋๋ ์์ ์ ํธ์ถํ ๋ ธ๋์ ์์๋ ธ๋๋ฅผ ๋ค๋ฅธ ๋ ธ๋๋ก ๊ต์ฒดํ๋ค. ์ด ๋ ๊ต์ฒด๋ oldChild๋ DOM์์ ์ ๊ฑฐ๋๋ค.
Node.prototype.removeChild(child)๋ ์ธ์๋ก ์ ํ childNode๋ฅผ DOM์์ ์ญ์ ํ๋ค.
์ถ์ฒ: ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive-์ด์
๋ชจ