먹짱(쇼핑몰 프로젝트) - 리팩토링(2) - 효율적으로 DOM 요소 찾기

ryan·2022년 5월 31일
0

학습자료

  • 또 다른 지적사항은 무지성으로 querySelector 선택자만을 사용하여 DOM 요소를 찾는 것이다.
  • 그렇다. 내 코드에는 querySelector와 querySelectorAll 이외에는 사용되지 않았다.
  • 정신적 스승인 zeroCho의 가르침 중 하나는 같은 역할을 하는 코드처럼 보여도 다른 동작을 하며, 그 차이를 알고 적절히 활용해야 한다고 했다.

기존 코드

코드 예시

const $itemSection = document.querySelector('#itemlist_section');
const $category1 = document.querySelector('#category_1');
const $category2 = document.querySelector('#category_2');
let $itemListFlexbox = document.querySelector('.itemlist_flexbox');
let $article = document.querySelectorAll('#itemlist');

문제점 분석

  • $itemListFlexbox를 제외하고 모두 id를 가져오지만 querySelector선택자만을 사용하고 있다.
  • $article의 경우 id지만 여러개의 element의 같은 id가 붙어있다. (class가 낫지 않을까...?)



❗ querySelector와 그 외의 차이점

존재하는 다양한 선택자들

  • 아래 코드 박스에서 보는 것과 같이 다양한 선택자가 존재한다. 이런 선택자는 왜 존재하는 거고, querySelector와의 차이가 무엇일까?
getElementById()
getElementsByClassName()
getElementsByName()
getElementsByTagName()

차이점 1. 성능

  • 최상단에 나온 자료를 확인한다면 getElementById를 통해 요소를 가져오는 방식이 querySelector보다 1.2배 빠르다고 한다
  • 하지만 결코 querySelector가 느린 건 아니다. 연산 결과 querySelector는 초당 7,000,000건의 작업을 처리할 수 있다.

차이점 2. 반환 타입(매우 중요)❗❗

  • getElementById는 id라는 용도 때문에 하나의 element를 반환하지만 그 외는 [HTMLCollection]으로 반환이 된다.
  • 똑같이 여러개의 노드를 반환하는 querySelectorAll의 경우는 [NodeList]로 반환이 된다.
  • HTMLCollection, NodeList의 차이는 아래와 같다.
    • HTMLCollection : live DOM(참조 개념). 선택한 요소(또는 요소들의 모임)의 변경사항이 발생하면 상태를 반영한다.
      • name, id attributes를 이용하여 접근가능
    • NodeList : non-live DOM(할당 개념). 실시간으로 상태를 반영하지 않는다.
      • childNodes 프로퍼티가 추가되면 실시간으로 상태를 반영한다.
        • index로 접근 가능

반환 타입 더 자세히 알아보기

  • getElementById는 HTMLElement를 반환한다.
  • HTMLCollection은 실시간 상태를 반영한다. 유사 배열이기 때문에 배열 메서드를 사용할 수 없다.
  • NodeList는 실시간 상태를 반영하지 않고, forEach를 제외한 다른 배열 메서드를 사용할 수 없다.

HTML Collection이 live dom이라는 건 처음 알게 돼서 dom을 노드의 변경사항이 생길 때마다 최신 상태로 계속 재할당하던 내 코드를 개선시켜볼 수 있을 것 같다.




❗ 그래서 어떻게 DOM 요소에 접근해야 할까?

  • 위의 내용대로라면 단순히 성능의 문제로 get메서드를 사용한다는 것은 모순이 있다.
  • querySelector도 충분히 빠르고 유연하게 사용할 수 있기 때문에 생산성에 도움을 줄 수 있기 때문이다.

하나의 특정 요소를 지정할 때

  • html 설계가 잘 돼서 class와 id의 구분이 명확하다는 가정하에, id의 값을 가져올 때는 getElementById를 통해 요소를 가져오는 것이 바람직하다. id는 특정 요소를 지정하기 위해 사용하기 때문이다.
  • 그 외의 특정 요소를 지정할 때는 querySelector가 나아보인다. CSS처럼 아주 디테일한 요소까지 특정할 수 있는 유연함을 활용할 수 있기 때문이다.

요소'들'을 가져올 때

  • 상황에 따라 적절히 사용하면 될 것 같지만, 개인적으로 querySelectorAll을 사용할 것 같다.
  • 그 이유는 생산성이다.
    1) 일단 querySelectorAll로 dom요소를 가져오는 코드의 일관성을 지킬 수 있고,
    2) 실시간 반영이 필요한 경우 childNodes를 활용하여 HTMLCollection 특성도 가질 수 있다.
    3) 무엇보다 노드의 상태값이 실시간으로 반영돼서 발생하는 문제도 무시할 수 없을 것 같다.




수정한 코드

  • 일단 get메서드를 활용해보고 싶어서 getElementsByClassName을 사용했지만 나중에 코딩을 할 때는 querySelectorAll을 위주로 사용할 것 같다.
  • 다시 보니... getElementsByClassName는 재할당이 필요없기 때문에, let을 안써도 됐을 것 같다.

코드 예시

❗ 코드를 알고 쓴다는 것

  • 이번 기회로 더 확실하게 느낀 것 같다.

    왜 get으로 가져온 노드들은 forEach가 안될까?
    왜 똑같이 요소를 가져오는데 반환 타입이 다르지?
    불편하게 왜 요소를 렌더링 시킬 때마다 재할당을 해줘야할까?

  • 이번에 학습을 안했으면 절대 몰랐을 개념이다. 유사 배열의 특성도 알게 됐고, 반환 타입에 대해 더 공부할 수 있었고, 코드의 생산성도 높일 수 있었다. 하나를 앎으로서 파생되는 효과가 매우 크다.

  • 언어는 계속해서 빠른 속도로 발전되고 있다. 특히 프론트엔드 생태계는 격변의 시기를 거치고 있다고들 말한다. 왜 프론트엔드 개발자에게 요구되는 가장 핵심적인 역량 중 하나가 '학습할 수 있는 태도'인지 조금이나마 공감할 수 있었다.

profile
프론트엔드 개발자

0개의 댓글