jquery 구현 원리 7: DOM 스트리밍-tranversing

하나, pushStack
tranversing 전에pushStack 함수를 언급해야 합니다. 이 함수는dom 작업에서 여러 번 사용되었습니다.이 함수는 매우 간단하게 실현된다.
    // Take an array of elements and push it onto the stack
    // (returning the new matched element set)
    pushStack: function( elems ) {

        // Build a new jQuery matched element set
        var ret = jQuery.merge( this.constructor(), elems );

        // Add the old object onto the stack (as a reference)
        ret.prevObject = this;
        ret.context = this.context;

        // Return the newly-formed element set
        return ret;
    },
        merge: function( first, second ) {
        var l = second.length,
            i = first.length,
            j = 0;

        if ( typeof l === "number" ) {
            for ( ; j < l; j++ ) {
                first[ i++ ] = second[ j ];
            }
        } else {
            while ( second[j] !== undefined ) {
                first[ i++ ] = second[ j++ ];
            }
        }

        first.length = i;

        return first;
    },

편의를 위해merge함수도 붙였다.
우선merge함수의 작용은 매우 간단하다.second의 원소를 모두first에 추가하는 것이다.
그리고 pushStack이 무엇을 했는지 한 줄 한 줄 보고,
1, var ret = jQuery.merge( this.constructor(), elems ); 이 코드는 빈 jquery 대상을 새로 만들고 elemsmerge를 넣었기 때문에 이것은 var ret = $(elems)에 해당합니다.(왜 직접 이렇게 쓰지 않고 복잡하게 만드는지 성능 때문인지 모르겠다)
2,ret.prevObject = this;  ret.context = this.context; 속성prevObject를 설정했습니다. 이 속성은pushStack 이전의query 대상을 저장합니다. 따라서query 대상을 여러 번 찾으면prevObject를 따라 되돌아갈 수 있습니다. 예를 들어 $('xx ').find('a').prevObject.xxx.context는 상하문을 기록하는 것으로 여러 window에서 사용할 수 있으며 상관하지 않아도 됩니다.
마지막으로ret로 돌아왔습니다.
그래서 총괄적으로 말하면pushStack 함수의 역할은 새로운 jquery 대상을 되돌려주는 것이다. 단지prevObject로 지난번에 선택한 대상을 기록할 뿐이다.
둘째, traversing 실현 원리
이 모듈은 단지 200여 줄의 코드만 있어서 매우 이해하기 쉬우므로 너무 많은 설명을 할 필요가 없다.
기본 구조를 말해 보세요. 코드 구조가 좋지 않으면 중복되는 코드가 많을 수 있으니까요.
우선, 가장 핵심적인 것은 다음과 같은 세 가지 함수이다.
jQuery.extend({
     filter: function( expr, elems, not ) {
          var elem = elems[ 0 ];

          if ( not ) {
               expr = ":not(" + expr + ")";
          }

          return elems.length === 1 && elem.nodeType === 1 ?
               jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
               jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
                    return elem.nodeType === 1;
               }));
     },

     dir: function( elem, dir, until ) {
          var matched = [],
               truncate = until !== undefined;

          while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
               if ( elem.nodeType === 1 ) {
                    if ( truncate && jQuery( elem ).is( until ) ) {
                         break;
                    }
                    matched.push( elem );
               }
          }
          return matched;
     },

     sibling: function( n, elem ) {
          var matched = [];

          for ( ; n; n = n.nextSibling ) {
               if ( n.nodeType === 1 && n !== elem ) {
                    matched.push( n );
               }
          }

          return matched;
     }
});

사실 작용과 실현은 모두 일목요연하다.
Filter는elems에서expr에 맞는 결과를 필터합니다
dir는 한 방향으로 옮겨다니는 것입니다. 예를 들어parentNode입니다. 끝날 때까지 옮겨다니는 조건은until입니다.
bling은 형제 노드를 두루 훑어보고 elem까지 두루 훑어본다. 이곳의 elem과dir의 until은 같은 작용을 한다. 모두 끝 요소이다. until이라고 불러야 하지 않겠는가?
그리고api를 정의했습니다. 모두 이 세 가지 함수를 호출해서 이루어진 것이기 때문에 할 말이 없고 더 이상 말하지 않겠습니다.
그 중의 실현, 어떻게 최대한의 복용 코드를 사용하는지 주의해라.
예를 들어 Filter와 not의 기능이 매우 비슷해서 이를 winnow 함수에 봉인했다.parent,next,prev 등 한 무더기의 함수도 매우 비슷하여 서로 다른 부분을 대상에 존재하고 이 대상을 옮겨다니며 인터페이스를 생성한다.

좋은 웹페이지 즐겨찾기