[TIL] appendChild는 항상 부모 노드의 마지막에 "새로" 추가하는 것은 아니다!

작성한 코드를 팀원이 읽어보는 과정에서 이상한 점이 발견되었다

해당 공간에 내용(객체 20개)이 들어있다
그 공간에 appendChild를 했는데 칸을 비우거나, 기존 내용을 삭제하는 코드가 없다
하지만 기존 공간에 노드가 존재하면서 새로운 노드가 추가되는 것이 아니라 대체가 된다
그것도 아무런 에러 메시지 없이..!

 

코드 설명

아래 코드는 클릭한 radio 버튼의 id에 따라 정렬된 카드를 화면에 추가하는 역할을 한다 (카드에는 영화 데이터가 들어있다)

switch 문 중 첫번째 case만 가져왔다

 

tempArr1에는 인수로 전달되는 문자열을 기준으로 정렬한 카드(노드) 배열에 들어있다

이 배열을 돌면서 $main_cards에 appendChild로 추가한다

($main_cards는 정렬된 카드가 들어갈 자리로, 필터링 결과 적용 전 현재 화면에 보이는 카드들이 들어 있다)

tempArr1

 

그럼 의도했던 정렬된 결과가 도출된다!

로딩 후 첫 화면
필터링 후 화면

 

이상하지 않은가?

기존 카드가 존재함에도 제거하는 코드 없이 20개라는 개수를 유지하면서, 정렬된 카드가 배치되었다

 

컴퓨터가 뭘 잘못하겠어 내 코드가 잘못된 것이겠지..

하지만 콘솔을 찍어 사용하는 모든 곳을 찾아봐도 $main_cards에서 기존 카드를 삭제하거나 변경하는 곳이 없었다 ? ??! ?

 

해당 코드가 기존 $main_cards에서 정렬된 카드를 만드는 정렬 함수이다

api를 받아오고 받아온 데이터를 따로 저장하는 것 없이 카드를 만들어 화면에 그리기 때문에, 현재 화면에 있는 카드 데이터를 가져오는 것이 필요했다

더보기

import로 따로 데이터를 가져오려했으나 화면에 그리는 함수(printMovieCard)는 app.js에서 단 한번 호출된다 

그리고 printMovieCard는 가져온 데이터(fetchMovies)로 카드를 만들어 화면에 붙이는 함수(createMovieCard)를 가지고 있기 때문에 해당 함수를 여러번 호출하는 것은 옳지 않다고 생각했다

 

결과적으로 빈 배열인 filterResults를 사용했고, 

비교하려는 값을 querySelector로 가져와 비교 후, 정렬된 배열을 반환한다

 

이전 사진에서 나온 sortFilter함수는 반환된 배열을 가지고 forEach를 돌면서 $main__cards에 appendChild 해주는 것이다

 

코드를 봤는데 이유를 찾을 수 있었는가?? ?

 

실제로 튜터님 두 분께 질문했는데 처음에는 답을 못얻었다

이외에도 모든 코드를 뒤지면서 찾아도 못찾음

 

콘솔로는 도저히 답이 안나왔는데 공식문서를 보니 단번에 알 수 있었다 ㅋㅋ

 

이유는 바로 appenChild 그 자체였다.. (레전드)

 

appendChild

공식 문서에 따르면 appendChild는 노드를 부모 노드의 자식 리스트 중 마지막 자식으로 붙인다

 

하지만 주어진 노드가 이미 문서에 존재하는 노드를 참조하는 경우, 현재 위치에서 새로운 위치로 이동 시킨다

즉, 문서에 존재하는 노드를 부모 노드에서 지울 필요가 없다는 것이다!

 

위 코드에서 targetA, targetB로 기존 노드를 가져왔기 때문에 추가 없이 새로운 위치로 이동된 것이었다

 

이번 프로젝트를 하면서 appendChild를 많이 썼는데 이런 기능은 처음봤다

그만큼 이런 기능을 대부분 잘 모른다는 뜻이겠지

 

See the Pen Untitled by Hayan Lee (@Hayan-Lee) on CodePen.

 

위 예제에서도 실행해보면 참조 값으로 가져온 $item은 항상 기존 위치에서 마지막 위치로 갱신된다