처음 자바스크립트로 돔을 만들고 추가하는 방법을 배울 때 보통
document.createElement()로 생성하고
appendChild()를 이용해 바로 DOM에 등록하게 된다.
[코드 예시]
<body>
<script>
for (let i = 0; i < 10; i++) {
let divEl = document.createElement("div");
divEl.innerText = "Hello, this is" + i;
document.body.appendChild(divEl);
}
</script>
</body>
// 화면에는 Hello, this is 1~10까지 나타나게 된다
**여기서 documentFragment 노드를 사용하면 오직 메모리상에만 존재하는 경량화된 DOM을 만들 수 있다.**
<body>
<script>
const docFrag = document.createDocumentFragment();
// documentFragment를 for문 밖에 생성하고
for (let i = 0; i < 10; i++) {
let divEl = document.createElement("div");
divEl.innerText = "Hello, this is" + i;
docFrag.appendChild(divEl);
// for문 내에 docFrag에 divEl을 붙여주고
}
document.body.appendChild(docFrag);
// body에 docFrag 노드를 붙여준다.
</script>
</body>
// 화면에는 똑같이 Hello, this is 1~10까지 나타나게 된다
**그럼 div요소를 하나 만들어 거기다 노드 트리를 만드는 것과 뭐가 다를까?**
<body>
<script>
const test = document.createElement("div");
for (let i = 0; i < 10; i++) {
let divEl = document.createElement("div");
divEl.innerText = "Hello, this is" + i;
test.appendChild(divEl);
}
document.body.appendChild(test);
</script>
</body>
// 화면에는 똑같이 Hello, this is 1~10까지 나타나게 된다
결과는 같다.
**DocumentFragment의 특징**
1. DocumentFragment를 DOM노드에 추가한다고 해도 DocumentFragment 노드는 등록되지 않고 그 자식 노드들만 추가된다.
즉, 개발자도구에서 HTML을 확인하면 div 태그 내에 묶음으로 추가된 div 노드들이 있다.
하지만 DocumentFragment로 만든 노드는 각각의 div태그로 구성되어 독립적인 것을 볼 수 있다.
2. DocumentFragment를 DOM에 추가하면 DocumentFragment의 노드의 자식요소들은 더 이상 메모리 상에 존재하지 않는다.
자식요소를 확인해보자. (childNodes 속성이용)
console.log(docFrag.childNodes); // 등록 전
document.body.appendChild(docFrag); // body에 등록
console.log(docFrag.childNodes); // 등록 후
결과는 아래와 같다. 등록 전에는 자식 노드들이 뜨지만, 등록 후에는 뜨지 않는다.
이러한 특징 때문에 요소를 여러 개의 각기 다른 부모 요소에 집어넣을 때 더욱 깔끔한 코딩이 가능하다.
코드 예제를 통해 다시 한 번 비교해보자
**[일반적인 제작방식]**
<body>
<div class="container"></div>
<div class="container"></div>
<div class="container"></div>
<script>
let element = [];
for(let i =0; i <100; i++){
const el = document.createElement("div");
element.push(el);
}
const cont = document.querySelectorAll(".container");
for(let i = 0; i< cont.length; i++){
for(let j =0; j< element.length; j++){
cont[i].appendChild(elements[j].cloneNode(true));
// 배열은 참조타입이기 때문에 clone을 해줘야 한다.
}
}
</script>
</body>
**[DocumentFragment 사용] - 가상 돔처럼 fragment에 넣어 그것을 사용**
<body>
<div class="container"></div>
<div class="container"></div>
<div class="container"></div>
<script>
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const el = document.createElement("div");
frag.appendChild(el);
}
const cont = document.querySelectorAll(".container");
for (let i = 0; i < cont.length; i++) {
cont[i].appendChild(frag.cloneNode(true));
}
</script>
</body>
**[정리]**
- DocumentFragment 노드는 오직 메모리상에만 존재하는 경량화된 노드이다.
- DocumentFragment를 DOM에 추가한다고 해도 DocumentFragment노드는 추가되지 않고
그 자식노드만 추가된다.
- DocumentFragment를 DOM에 추가할 떄, DocumentFragment의 자식 노드는 더 이상 생성한 메모리상의 위치에 존재하지 않는다. 만약 이를 유지시키고 싶다면 cloneNode를 통해 복제하는 방법이 있다.
(cloneNode를 이용해 자식을 복사하면 frag.childNodes를 통해 자식을 확인할 수 있다.)
(인프런 "코딩인터뷰를 저격하는 JS 스나이퍼 양성학교" 참고)