문제 상황
의도한 동작 & 코드 & 결과
원인 찾기
원인
해결 방법
추가 내용
정리
회고
이전에는 모든 요소를 삭제하는 경우에 querySelectorAll
로 골라서 삭제하거나 아예 새로운 List를 만들어서 교체하는 방식으로 구현을 했었다. 이번에는 DOM을 학습하면서 한 번도 안써본 Element.Children
, Node.removeChild()
, Element.remove()
를 사용하는 과정에서 문제가 발생했다.
한 일 모두 지우기
버튼 클릭시 checked
된 아이템을 전부 화면에서 제거하기const list = document.querySelector('.list');
const btn = document.querySelector('button');
const items = list.children; // HTMLCollection
btn.addEventListener('click', removeCheckedItems);
function removeCheckedItems() {
for (const item of items) {
item.firstChild.checked && list.removeChild(item);
}
}
<body>
<ul id="world" class="list">
<li class="item item0"><input type="checkbox" checked />할 일 0</li>
<li class="item item1"><input type="checkbox" checked />할 일 1</li>
<li class="item item2"><input type="checkbox" checked />할 일 2</li>
<li class="item item3"><input type="checkbox" checked />할 일 3</li>
<li class="item item4"><input type="checkbox" checked />할 일 4</li>
<li class="item item5"><input type="checkbox" checked />할 일 5</li>
</ul>
<button type="button">한 일 모두 지우기</button>
</body>
items
를 for...of
로 순회하면서 해당 input이 checked
이면 list
에서 해당 item
을 제거도록 작성했다.list.children
은 콘솔에 찍어봤을 때 배열의 형태를 보여서 배열을 반환한다고 짐작했다. querySelectorAll()
도 배열을 반환한다고 생각(forEach 메소드를 갖고 있어서)하고 있었어서 둘 다 배열을 반환한다고 생각했다. 그리고 결정적으로 for...of
를 사용할 수 있어서 더 배열이라고 믿었다...HTMLCollection
, Static NodeList
을 리턴한다.for-of
문은 3번 반복됐다.HTMLCollection
는 배열이 아니다.Element.children
가 반환한 HTMLCollection
가 배열이 아닐 수 있겠다는 생각이 들었다.items
를 isArray()
로 확인해보니 false
가 나왔다.function removeCheckedItems() {
items.forEach(item => {
item.firstChild.checked && list.removeChild(item);
});
}
HTMLCollection
은?HTMLCollection 인터페이스는 요소의 문서 내 순서대로 정렬된 일반 컬렉션(arguments처럼 배열과 유사한 객체)을 나타내며 리스트에서 선택할 때 필요한 메서드와 속성을 제공합니다.
HTML DOM 내의 HTMLCollection은 문서가 바뀔 때 실시간으로 업데이트됩니다.https://developer.mozilla.org/ko/docs/Web/API/HTMLCollection
HTMLCollection
은 배열이 아니고 순서대로 정렬된 배열과 유사한 객체이다.length
, 메서드로는 인덱스의 값을 반환하는 item()
이 있는데 for...of
를 쓸 수 있게 억지로 만든 느낌?? 이다.DOM 컬렉션 객체
다. 유사배열객체
이자 이터러블
이다.HTMLCollection
은 실시간으로 업데이트된다. DOM에 변경이 생기면 자동으로 업데이트가 되서 MDN에서는 adding, moving, or removing nodes
를 할 때 복사본을 만들어서 하는 걸 추천한다.HTMLCollection
의 Live
한 속성 때문에 발생했다.(index 0, 1, 2)
난 이후 index 3
의 값이 없기 때문에 종료됐다.const list = document.querySelector('.list');
const btn = document.querySelector('button');
const items = list.children; // HTMLCollection
btn.addEventListener('click', removeCheckedItems);
// forEach
function removeCheckedItems1() {
const arrayItems = Array.from(items);
arrayItems.forEach(item => {
item.firstChild.checked && list.removeChild(item);
});
}
// for...of
function removeCheckedItems2() {
const arrayItems = Array.from(items);
for (const item of arrayItems) {
item.firstChild.checked && list.removeChild(item);
}
}
Array.from
으로 배열로 변환 후에 forEach
, for...of
를 사용했다.Element.children
대신 querySelectorAll()
를 사용한다.const list = document.querySelector('.list');
const btn = document.querySelector('button');
const items = list.querySelectorAll('.item'); // NodeList
btn.addEventListener('click', removeCheckedItems);
function removeCheckedItems() {
items.forEach(item => {
if (item.firstChild.checked) list.removeChild(item);
});
}
querySelectorAll()
은 Static NodeList
를 반환하는데 이것도 HTMLCollection
와 같은 유사배열객체이지만 Live
속성이 없다.NodeList
는 내부 요소들을 순회할 수 있는 forEach
메소드를 가진다.querySelectorAll()
은 Static NodeList
를 반환한다.https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
https://developer.mozilla.org/en-US/docs/Web/API/NodeList
NodeList
는 HTMLCollection
과 같이 DOM 컬렉션 객체다. 유사배열 객체이면서 이터러블이다.NodeList
는 Live 와 Static 두 가지가 있다. Live
는 위에서 본 HTMLCollection
처럼 실시간 업데이트가 된다. Node.childNodes
가 Live NodeList
를 반환한다.querySelectorAll()
는 Static NodeList
를 반환하는데 이름 그대로 정적이라서 어떠한 변경도 원본 리스트에 영향을 주지 못한다. 그래서 이번에 발생한 문제가 생기지 않는다.HTMLCollection
보다 다양한 메소드를 갖는다. item()
, entries()
, forEach()
, keys()
, values()
HTMLCollection
NodeList
는 DOM 컬렉션 객체이며 유사배열객체이고 이터러블이다.HTMLCollection
Live
(살아있는) 객체이다.NodeList
querySelectorAll()
로 만들어졌을 경우에 Static
childNodes
프로퍼티로 반환한 경우 Live
배열
로 변환해 사용하면 된다.NodeList
는 forEach
메소드가 있지만, 배열로 변환하면 다양한 고차함수까지도 안전하게 사용할 수 있다.제대로 아는 게 중요하는 걸 깨닫는다.
아직 경험이 적지만 현재 내 수준에서 겪는 문제들은 거의 정확하게 알지 못해서 발생하는 것 같다. 이번에도 단순히 콘솔에서 []
으로 감싸져 있다고 배열이라고 짐작했다. mdn에 검색해보기만 하면 나오는 것인데... 하지만 이제 제대로 안다는 것이 기쁘고 문제를 해결한 것이 뿌듯하다.
https://developer.mozilla.org/en-US/docs/Web/API/NodeList
https://developer.mozilla.org/ko/docs/Web/API/HTMLCollection
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll