Array.prototype.sort
를 사용할 수 없다는 점이다. 따라서 Array.prototype.sort
.call(bodyElement.childNodes, (a, b) => {
const bookNameNode1 = a.childNodes[1];
const bookNameNode2 = b.childNodes[1];
return bookNameNode1.innerText > bookNameNode2.innerText
? 1
: bookNameNode1.innerText < bookNameNode2.innerText
? -1
: 0;
})
.forEach((node) => bodyElement.appendChild(node));
위와 같이 코드를 짜봤다. 하지만,
Uncaught TypeError: Failed to set an indexed property on 'NodeList': Indexed property setter is not supported.
위와 같은 에러를 리턴했다. 찾아보니 브라우저 별로 다르긴 하지만, nodelist에 대해서 인덱스를 변경하는 행위를 브라우저 단에서 막는다고 한다. 생각해보면 이 접근법은 접근 자체가 틀린게 sort를 하기전에 일단 유사 배열 객체를 아예 배열로 먼저 바꿔 줬어야했다. 따라서 다른 방법을 떠올려야 했고, 결론적으로 이와 같이 해결했다.
[...bodyElement.children]
.sort((a, b) => {
const bookNameNode1 = a.childNodes[1];
const bookNameNode2 = b.childNodes[1];
return bookNameNode1.innerText > bookNameNode2.innerText
? 1
: bookNameNode1.innerText < bookNameNode2.innerText
? -1
: 0;
})
.forEach((node) => bodyElement.appendChild(node));
위와 같이 먼저 유사배열 객체를 Array.prototype
을 가리키는 실제 JS 내에 배열로 만들어줬고, 그 다음에 sort를 적용했다. 이 때, 유사배열 객체를 배열로 바꾸는 방법은 아래와 같이도 해줄 수 있다.
Array.prototype.slice.call(bodyElement.children)
처음에 sort를 할 때 바로 유사배열객체를 this 바인딩 커스텀으로 해결하려 했던게 문제였고, 잘못 접근했음을 알고 수정하여 해결했다.
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app">
Hello, world!
<div>Hello, world!</div>
</div>
<script src="src/index.js"></script>
</body>
</html>
그리고 아래는 js 파일이다.
const divElement = document.querySelector("#app");
console.log(divElement.innerHTML);
console.log(divElement.innerText);
console.log(divElement.textContent);
전체 내용
을 가져온다. 예시의 결과를 보면 Hello, world!
<div>Hello, world!</div>
다음과 같이 출력된걸 볼 수 있다. 즉, 위에서 말한대로 innerHTML은 해당 속성을 호출한 노드 내부의 전체 내용을 string 형태로 가져온다. 다음으로 innerText와 textContent를 보면, 아래와 같이 출력이 동일하다.
Hello, world!
Hello, world!
그럼 둘은 똑같은걸까? nope.
<div id="app">
Hello, world!
<div style="display: none;">Hello, world!</div>
</div>
이런식으로 id = app 인 div 내에 또 다른 div에 display:none;
속성을 줘봤다. 그랬더니 결과가 달라졌다. 먼저 innerText에서는
Hello, world!
이렇게 출력됐다. 이는 innerText가 보이는 내부 텍스트
만 출력하는 것을 알 수 있는 부분이다. 그럼 textContent는 ?
Hello, world!
Hello, world!
여전히 보이는, 보이지 않는 텍스트 모두
를 출력하고 있었다. 이에 따라 둘의 차이를 알 수 있었다.
Node.appendChild(specificNode)
를 썼을 때, 특정 Node의 children 중에 'specificNode' 가 이미 있다면, 그 노드를 새로운 위치(appendChild니까 맨 끝에)에 추가하는 식으로 동작한다. 즉, specificNode이 이미 있다했을 때 새로운 노드를 append 하는게 아니라 이미 있는걸 새로운 위치에 append 하는거다. [...bodyElement.children]
.sort((a, b) => {
const bookNameNode1 = a.children[1];
const bookNameNode2 = b.children[1];
return bookNameNode1.innerText > bookNameNode2.innerText
? 1
: bookNameNode1.innerText < bookNameNode2.innerText
? -1
: 0;
})
.forEach((node) => bodyElement.appendChild(node));
위에서 sort 로직을 위와 같이 짰었는데, 생각해보니까 sorting을 한 array에 대해 forEach로 appendChild를 하면 직관적으로 생각하면 같은 node가 새로운 위치에 하나 더 추가돼서 중복되는 노드들이 생겨 이전보다 2배 많은 노드들이 생기는 결과가 나와야하지 않나? 했는데 appendChild 자체가 동작 방향이 앞서 말한 것처럼 이미 있는걸 바탕으로 움직이므로(이미 있는 경우에 한하여) 저렇게 코딩해도 정상적으로 작동함을 알 수 있었다.
많은 도움이 되었습니다, 감사합니다.