jQuery 선택자 — 원하는 요소를 골라내는 가장 빠른 길

jQuery로 하는 거의 모든 작업은 “무엇을 고를 것인가”에서 시작합니다. 고르는 일이 정확해지면 나머지는 메서드 하나를 붙이는 것으로 끝납니다. 이 글에서는 선택자를 넓게 잡았다가 점점 좁혀 가는 순서로, 기본 선택자부터 필터와 탐색 메서드, 체이닝까지 살펴봅니다.

1단계: CSS와 똑같은 세 가지 기본 선택자

jQuery 선택자의 가장 큰 장점은 새로 외울 것이 거의 없다는 점입니다. CSS에서 쓰던 표현을 따옴표 안에 그대로 넣으면 됩니다.

$('p')            // 모든 <p> 태그
$('#mainNote')    // id가 mainNote인 요소 하나
$('.note-card')   // class가 note-card인 요소 전부

$('.note-card p')      // 카드 안에 있는 모든 문단 (후손)
$('.note-card > p')    // 카드의 바로 아래 문단만 (자식)
$('h3, h4')            // 두 종류를 한꺼번에

여기서 기억할 규칙이 하나 있습니다. #은 문서에 하나뿐인 이름이라 결과가 최대 한 개지만, 태그와 클래스는 몇 개가 잡히든 한 덩어리로 묶여 돌아온다는 점입니다. 그래서 $('.note-card').hide()는 반복문 없이 카드 전체를 감춥니다. 순수 자바스크립트라면 querySelectorAll로 목록을 받은 뒤 forEach를 돌려야 하는 부분입니다.

2단계: 속성으로 더 좁히기

클래스가 붙어 있지 않은 요소를 골라야 할 때가 있습니다. 특히 폼 안의 입력칸이 그렇습니다. 이때는 대괄호 안에 속성 조건을 씁니다.

$('input[type="checkbox"]')   // 체크박스만
$('a[target]')                // target 속성이 있는 링크 전부
$('a[href^="/course"]')       // href가 /course로 시작하는 링크
$('img[src$=".png"]')         // src가 .png로 끝나는 이미지
$('a[href*="jquery"]')        // href에 jquery가 들어간 링크

기호 세 개만 구분하면 됩니다. ^는 시작, $는 끝, *는 포함입니다. 여기 쓰인 $는 jQuery 함수와 아무 관련이 없고 “문자열의 끝”을 뜻하는 별개의 표시입니다.

3단계: 필터로 순서와 조건 지정하기

이미 고른 묶음에서 몇 번째만 남기고 싶다면 콜론으로 시작하는 필터를 붙입니다.

필터 고르는 대상
:first 묶음의 첫 번째 요소 하나
:last 묶음의 마지막 요소 하나
:even 0, 2, 4번째 (0부터 셉니다)
:odd 1, 3, 5번째
:not(조건) 조건에 맞지 않는 요소
:contains('글자') 해당 글자를 품고 있는 요소
$('.note-card:first').addClass('featured');
$('#courseTable tr:even').css('background', '#f7f7f7');
$('.note-card:not(.draft)').show();

여기서 입문자가 거의 예외 없이 걸리는 지점이 :even입니다. 사람은 첫 번째 줄을 홀수로 세지만 jQuery는 0번부터 셉니다. 그래서 표의 첫 줄에 색을 넣고 싶으면 :odd가 아니라 :even을 써야 합니다. 줄무늬 색이 한 칸씩 밀려 보인다면 대부분 이 문제입니다.

4단계: 이미 선 자리에서 이동하는 탐색 메서드

선택자는 문서 전체에서 찾는 방식이고, 탐색 메서드는 지금 고른 요소를 기준으로 가족 관계를 따라 이동하는 방식입니다. 클릭된 버튼 하나를 기준으로 주변을 다룰 때 특히 유용합니다.

var $card = $('#note12');

$card.find('.tag');      // 카드 안쪽 모든 깊이에서 .tag 찾기
$card.children('p');     // 바로 아래 자식 중 문단만
$card.parent();          // 카드를 감싼 부모 하나
$card.closest('section');// 위로 올라가며 만나는 첫 section
$card.siblings();        // 나를 뺀 형제들
$card.eq(0);             // 묶음에서 0번째 하나만

findchildren은 비슷해 보이지만 깊이가 다릅니다. children은 딱 한 층 아래만 보고, find는 몇 층이든 파고듭니다. 카드 안에 <div>로 한 번 더 감싼 태그가 있는데 children('.tag')로 찾으면 결과가 0개가 나옵니다.

그리고 결과가 0개여도 jQuery는 오류를 내지 않습니다. 조용히 아무 일도 하지 않을 뿐입니다. 선택이 제대로 됐는지 확인하려면 console.log($('.tag').length)로 개수를 먼저 찍어 보는 습관이 필요합니다.

5단계: 체이닝으로 한 줄에 이어 쓰기

jQuery 메서드는 대부분 작업을 마친 뒤 자기 자신을 다시 돌려줍니다. 그래서 점을 찍어 계속 이어 붙일 수 있고, 이것을 체이닝이라고 부릅니다.

$('#note12')
  .addClass('active')
  .find('.tag')
    .css('color', '#c0392b')
  .end()
  .siblings()
    .removeClass('active');

find로 안쪽에 들어가면 그 뒤 메서드는 모두 .tag에 적용됩니다. end()는 한 단계 전으로 되돌아오라는 뜻이라, 그 뒤의 siblings()는 다시 #note12를 기준으로 동작합니다. 체이닝이 길어지면 위 예시처럼 줄을 바꾸고 들여쓰기로 깊이를 표시해야 나중에 읽을 수 있습니다.

선택자를 익혔다면 다음은 고른 요소의 내용을 바꿀 차례입니다. jQuery DOM 조작으로 이어집니다. $의 정체가 아직 헷갈린다면 jQuery 입문을 먼저 확인하시기 바랍니다.

핵심 정리

  • 기본 선택자 — CSS 문법을 그대로 쓰며, 여러 개가 잡혀도 반복문 없이 한 번에 처리됩니다.
  • 속성 선택자^ 시작, $ 끝, * 포함으로 조건을 좁힙니다.
  • 필터:even:odd는 0부터 세므로 첫 줄이 짝수 취급을 받습니다.
  • 탐색 메서드children은 한 층, find는 모든 깊이를 뒤집니다.
  • 조용한 실패 — 선택 결과가 0개여도 오류가 없으므로 length로 확인해야 합니다.