let nodeListToArray = Array.from(targetElement.childNodes);
ES6의 Array.from() 정적 메서드를 사용하면 더 간결하게 변환할 수 있습니다. let nodeListToArray = Array.from(targetElement.childNodes); 모든 노드는 parentNode 속성을 가지며, 이는 DOM 트리에서 부모 요소를 가리킵니다. childNodes의 모든 노드는 동일한 부모 요소를 공유하므로, parentNode 속성은 동일한 노드를 가리킵니다. 또한, childNodes 목록의 각 노드는 다른 노드들과 형제(sibling) 관계를 가집니다. previousSibling과 nextSibling 속성을 사용하면 이 목록의 노드들 간을 탐색할 수 있습니다. 이 목록의 첫 번째 노드의 previousSibling 속성은 null이며, 마지막 노드의 nextSibling 속성도 null입니다:
if (targetElement.nextSibling === null){
alert("부모의 childNodes 목록의 마지막 노드입니다.");
} else if (targetElement.previousSibling === null){
alert("부모의 childNodes 목록의 첫 번째 노드입니다.");
}
만약 childNodes에 단 하나의 노드만 존재한다면, 그 노드의 previousSibling과 nextSibling 속성은 모두 null입니다.
부모 노드와 첫 번째 및 마지막 자식 노드는 각각 firstChild와 lastChild 속성을 통해 접근할 수 있습니다.
targetElement.firstChild의 값은 항상 targetElement.childNodes[0]과 같으며, targetElement.lastChild의 값은 항상 targetElement.childNodes[targetElement.childNodes.length-1]과 같습니다. 자식 노드가 하나만 있다면, firstChild와 lastChild는 동일한 노드를 가리킵니다. 자식 노드가 없다면, firstChild와 lastChild는 모두 null입니다. 이러한 노드 간의 관계는 문서 트리의 노드들 간을 탐색하는 데 편리함을 제공합니다.
이러한 관계 덕분에 childNodes 속성은 단순한 필수 속성 이상의 역할을 수행합니다. 이러한 관계 포인터를 활용하면 문서 트리의 거의 모든 노드에 접근할 수 있으며, 이는 childNodes의 가장 큰 장점입니다. hasChildNodes()라는 편리한 메서드도 있습니다. 이 메서드는 true를 반환하면 해당 노드가 하나 이상의 자식 노드를 가지고 있음을 의미합니다. childNodes의 length 속성을 조회하는 것보다 이 메서드가 더 편리합니다.
마지막으로, 모든 노드가 공유하는 관계가 하나 있습니다. ownerDocument 속성은 전체 문서를 나타내는 문서 노드를 가리키는 포인터입니다. 모든 노드는 생성된 문서(또는 속한 문서)에 소속되며, 하나의 노드가 동시에 두 개 이상의 문서에 존재할 수는 없습니다. 이 속성은 문서 구조를 거슬러 올라가지 않고도 문서 노드에 빠르게 접근할 수 있는 편의를 제공합니다.
모든 관계 포인터는 읽기 전용이므로, DOM은 노드를 조작하는 몇 가지 메서드를 제공합니다. 가장 일반적으로 사용되는 메서드는 appendChild()이며, 이는 childNodes 목록의 끝에 노드를 추가합니다. 새 노드를 추가하면 부모 노드와 이전 마지막 자식 노드의 관계 포인터가 업데이트됩니다. appendChild() 메서드는 추가된 새 노드를 반환합니다:
let newNode = document.createElement("div");
let appendedNode = parentElement.appendChild(newNode);
alert(appendedNode == newNode); // true
alert(parentElement.lastChild == newNode); // true
문서에 이미 존재하는 노드를 appendChild()에 전달하면, 해당 노드는 이전 위치에서 새 위치로 이동됩니다. DOM 트리는 다양한 관계 포인터로 유지되지만, 하나의 노드가 문서에서 동시에 두 곳 이상에 존재할 수는 없습니다. 따라서 부모 요소의 첫 번째 자식 노드를 appendChild()에 전달하면, 이 노드는 부모 요소의 마지막 자식 노드가 됩니다:
// parentElement에 여러 자식 노드가 있다고 가정
let movedNode = parentElement.appendChild(parentElement.firstChild);
alert(movedNode == parentElement.firstChild); // false
alert(movedNode == parentElement.lastChild); // true
// 마지막 자식 노드로 삽입
movedNode = parentElement.insertBefore(newNode, null);
alert(newNode == parentElement.lastChild); // true
노드를 childNodes 목록의 특정 위치(끝이 아닌)에 추가하려면 insertBefore() 메서드를 사용할 수 있습니다. 이 메서드는 두 개의 매개변수를 받습니다: 추가할 노드와 참조 노드. 이 메서드를 호출하면 추가할 노드는 참조 노드의 이전 형제 노드가 되며, 반환된 노드가 반환됩니다. 참조 노드가 null이면 insertBefore()는 appendChild()와 동일한 효과를 냅니다:
// 새로운 첫 번째 자식 노드로 삽입
insertedNode = parentElement.insertBefore(newNode, parentElement.firstChild);
alert(insertedNode == newNode); // true
alert(newNode == parentElement.firstChild); // true
// 마지막 자식 노드 앞에 삽입
insertedNode = parentElement.insertBefore(newNode, parentElement.lastChild);
alert(newNode == parentElement.childNodes[parentElement.childNodes.length - 2]); // true
appendChild()와 insertBefore()는 노드를 삽입할 때 기존 노드를 삭제하지 않습니다. 대신, replaceChild() 메서드는 두 개의 매개변수를 받습니다: 추가할 노드와 교체할 노드. 교체할 노드는 반환되어 문서 트리에서 완전히 제거되며, 추가할 노드가 그 자리를 대체합니다. 다음 예시를 살펴보겠습니다:
let replacedNode = parentElement.replaceChild(newNode, parentElement.firstChild);
replacedNode = parentElement.replaceChild(newNode, parentElement.lastChild);
replaceChild()를 사용하여 노드를 삽입한 후, 모든 관계 포인터는 교체된 노드로부터 복사됩니다. 교체된 노드는