이번 글에서는 예제 코드를 통해 jQuery 소스에서 많이 사용되는 each() 메서드에 대해서 알아보자.
다음 예제 코드의 실행 결과를 추측해보자.이 예제는 jQuery API 사이트에서 each 메서드를 설명한 http://api.jquery.com/each/의 예제 코드다. 예제는 비록 간단하지만, 이를 제대로 이해하기 위해서는 몇가지 지식이 필요하다.
예제1 - HTML 파트
예제2 - JS 파트
이 예제를 jQuery 소스를 살펴보면서 하나씩 살펴보자.
$('li') 살펴보기
가장 먼저 $(‘li’)라는 부분이 실행될 것이다. $() 함수는 결국 jQuery 생성자 함수를 통해 jQuery 객체를 생성하는 역할을 한다. 아래 코드는 jQuery 객체의 생성자 함수를 나타낸다. 참고로 jQuery 생성자 함수(init 함수)는 context라는 인자를 받는 데, jQuery 소스에서 context는 주로 document 객체를 가리킨다.
예제3 - jQuery 생성자 함수
$(‘li’)의 경우는 ‘li’가 “string” 타입이지만, html이나 id 문자열이 아니기 때문에 위 생성자 코드에서 다음과 같은 부분이 실행된다.
예제4 - jQuery 생성자 함수 일부
이 경우 jQuery(context)라는 jQuery 객체를 먼저 생성 후, 이 객체의 find() 메서드를 실행하게 된다. 따라서 다시 jQuery 객체를 생성하기 위한 생성자 함수가 실행되는데, 이때는 다음과 같은 부분이 실행된다. jQuery( context )에서 context 인자값이 undefined이므로 아래 생성자 함수의 selector 매개변수에 undefined가 전달된다. selector는 undefined의 경우는 document(DOM element)가 저장되면서 jQuery 객체를 리턴하게 된다.
예제5 - jQuery 생성자 함수 일부
이제 document를 포함하는 jQuery 객체를 만들었으니, find()메서드를 살펴보자. 코드는 다음과 같으며, selector에는 여전히 ‘li’가 전달된다. 코드가 상당히 복잡하다. 그래도 하나씩 살펴보도록 하자.
예제6 - $().find() 메서드 코드
우선 jQuery.map() 메서드의 실행 결과 값을 elems 변수에 저장한다. 따라서, jQuery.map() 메서드를 다시 분석해야 한다. 코드는 다음과 같다. 위 코드에서 인자로 넘긴 this는 find 메서드를 호출한 객체, 즉 위에서 생성한 Document를 가리키는 jQuery 객체다.
예제7 - jQuery.map() 메서드
jQuery.map() 메서드를 살펴보면, 인자로 elems와 callback 함수를 받는다. elems는 배열이고, callback은 콜백 함수가 넘겨질 것이다. jQuery.map() 메서드 내부에서는 elems 배열과 인덱스 값을 callback 함수를 호출해서 생성되는 리턴값을 ret 배열로 만든 다음 이를 다시 리턴한다. 다시 말하면, jQuery.map() 메서드는 ‘콜백 함수(기존 배열) ⇒ 새로운 배열’ 이렇게 생각하면 된다. 우리가 살펴보고 있는 예제에서는 elems는 this를 가리키는 데, this는 length가 0인 유사 배열 객체로 document를 가리키는 jQuery 객체다. 때문에 jQuery.map() 메서드 내에서는 for 루프가 한번만 돌며 다음과 같은 콜백 함수를 실행시킬 것이다. 여기서 인자로는 this가 전달된다.
예제8 - jQuery.map() 메서드로 전달되는 콜백 함수
결국 위 콜백 함수 jQuery.find(“li”, this)의 결과값이 jQuery.map() 메서드의 실행 결과가 된다. 이 결과값을 알아보기 위해서는 jQuery.find() 메서드 코드를 살펴보자.
예제9 - jQuery.find() 메서드의 일부
jQuery.find() 함수는 주어진 컨텍스트 내에서 셀렉터 값을 가진 DOM 요소를 찾는 메서드이다. jQuery는 다양한 셀렉터 형식을 지원하고 있다. 우리가 살펴볼 예제에서는 단순히 ‘li’라는 html 태그명만을 넘겼다. 이해를 돕기위해 예제9는 jQuery.find() 메서드 코드에서 태그명을 셀렉터로 넘겼을 때 처리되는 주요 부분만을 간추린 것이다.
전체적인 동작은 다음과 같다.
1. 정규표현식을 통해 셀렉터 형식 체크 –> 예제에서는 셀렉터가 태그임을 인식
2. 주어진 컨텍스트(여기서는 document)내에서 해당 태그를 가진 DOM 요소 검색 –> getElementsByTag() 메서드 이용
3. 검색된 DOM 요소 배열을 리턴
따라서 이번 예제에서 우리가 찾으려는 jQuery.find(“li”, this);의 결과값은 맨 처음 HTML 코드 예제1에서 <li> 태그를 가진 두 개의 DOM 요소가 될 것이다.
이제 다시 예제6으로 돌아가보자.
원래 구하려고 했던 jQuery.map() 메서드의 결과값은 결국 예제1의 <li> 태그를 가진 DOM 요소 객체이며, 이는 elems 변수에 저장된다. 이후 pushStack() 메서드가 호출된다.
예제10 - .pushStack() 메서드
예제10의 코드를 통해 .pushStack()의 기능을 살펴보면, elems 인자로 전달된 DOM 요소에 매핑되는 jQuery 객체를 새로 생성하고 생성된 객체의 prevObject 프로퍼티에 현재 jQuery 객체를 설정한다. (일종의 스택 추가 작업)
그리고 새로 생성된 jQuery 객체를 반환한다. 이 값은 결국 예제4의 리턴값이 된다.
이제 예제2에서 $(‘li’) 부분에 대해 jQuery 소스 코드의 내부 동작 과정에 대해서 살펴봤다. 이를 그림으로 정리하면 다음과 같다.
$('li').each() 살펴보기
이제 다시 예제2로 돌아가보자. 이 부분을 이해하기 위해서는
each()
설명 부분을 먼저 알아야 한다. 간단히 설명하자면 이 메서드는 jQuery 객체에 매핑된 DOM 요소들을 루프를 돌면서 콜백 함수를 실행하는 역할을 한다. 우리는 앞부분에서 $(‘li’)가 나타내는 jQuery 객체가 예제1의 두개의 li 태그를 매핑하고 있다는 것을 살펴봤다. 그러므로 예제2는 이 매핑된 두개의 DOM 객체에 대해서 아래 콜백 함수를 실행하는 역할을 한다.
예제11 - 콜백함수
이제 마지막으로 콜백 함수를 살펴보자.
this가 가리키는 것은 무엇일까?? this는 콜백 함수 내부에 있기 때문에, 콜백 함수를 호출하는 객체가 바로 this일 것이다.
each()
에서 설명했듯이, .each() 메서드 실행 시에 콜백 함수를 호출하는 주체는 바로 jQuery 객체에 매핑되어 있는 DOM 객체들이다. 따라서, 이 예제의 경우는 ‘li’ 태그 DOM 객체가 this에 해당한다.
이제 위 예제의 $(this)는 DOM 객체를 selector로 넘겨서 jQuery 객체를 생성한다는 것을 알 수 있다. 예제12는 jQuery 생성자 함수중 selector가 DOM 객체일 때, jQuery 객체를 생성하는 부분이다.
예제12 - jQuery 생성자 함수 일부
이 과정을 정리하면 아래 그림과 같이 나타낼 수 있다.
이제 마지막 .text() 메서드를 호출하면 된다. 이 메서드는 jQuery 객체와 매핑된 DOM 요소들(자식 노드 포함)의 text 부분을 묶어서 출력하는 역할을 한다. 자세한 설명은
text() 메서드
기사를 참조해라.
이제 지금까지의 상황을 종합해서 출력 결과를 알아보면 다음과 같다.
우선 예제1의 출력 결과는 다음과 같다.