jQuery技术内幕之总体架构与初始化函数

总体架构

  首先我们来看下在家在jquery的时候发生了什么,jquery的源码最外层的结构为:

(function( global, factory ) {
    if ( typeof module === "object" && typeof module.exports === "object" ) {
        ...  
    } else {
        factory( global );
    }
}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
    var jQuery;
    var strundefined = typeof undefined;
    ...
    if ( typeof noGlobal === strundefined ) {
      window.jQuery = window.$ = jQuery;
    }
}));

构造jquery对象

  接下来看工厂方法是如何创建jquery对象的

function( window, noGlobal ) {
    ......
    var jQuery = function( selector, context ) {
        return new jQuery.fn.init( selector, context );
    };
    jQuery.fn = jQuery.prototype = {
        ......
    };
    jQuery.extend = jQuery.fn.extend = function() {
        ......
    };
    ......
    var init = jQuery.fn.init = function( selector, context ) {};
    init.prototype = jQuery.fn;
    ......
    if ( typeof noGlobal === strundefined ) {
        window.jQuery = window.$ = jQuery;
    }
    return jQuery;
}

  下面我们再来看window对象的jQuery构造函数是如何创建jQuery实例的

var rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/;
init = jQuery.fn.init = function( selector, context ){
        var match, elem;
        if ( !selector ) {
            return this;
        }
        if ( typeof selector === "string" ) {
            if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
                match = [ null, selector, null ];
            } else {
                match = rquickExpr.exec( selector );
            }
            if ( match && (match[1] || !context) ) {
                if ( match[1] ) {
                    context = context instanceof jQuery ? context[0] : context;
                    jQuery.merge( this, jQuery.parseHTML(
                        match[1],
                        context && context.nodeType ? context.ownerDocument || context : document,
                        true
                    ) );
                    if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
                        for ( match in context ) {
                            if ( jQuery.isFunction( this[ match ] ) ) {
                                this[ match ]( context[ match ] );
                            } else {
                                this.attr( match, context[ match ] );
                            }
                        }
                    }
                    return this;
                } else {
                    elem = document.getElementById( match[2] );
                    if ( elem && elem.parentNode ) {
                        this.length = 1;
                        this[0] = elem;
                    }
                    this.context = document;
                    this.selector = selector;
                    return this;
                }
            } else if ( !context || context.jquery ) {
                return ( context || rootjQuery ).find( selector );
            } else {
                return this.constructor( context ).find( selector );
            }
        } else if ( selector.nodeType ) {
            this.context = this[0] = selector;
            this.length = 1;
            return this;
        } else if ( jQuery.isFunction( selector ) ) {
            return typeof rootjQuery.ready !== "undefined" ?
                rootjQuery.ready( selector ) :
                selector( jQuery );
        }
        if ( selector.selector !== undefined ) {
            this.selector = selector.selector;
            this.context = selector.context;
        }
        return jQuery.makeArray( selector, this );
}
var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
jQuery.parseHTML = function( data, context, keepScripts ) {
    if ( !data || typeof data !== "string" ) {
        return null;
    }
    if ( typeof context === "boolean" ) {
        keepScripts = context;
        context = false;
    }
    context = context || document;
    var parsed = rsingleTag.exec( data ),
        scripts = !keepScripts && [];
    if ( parsed ) {
        return [ context.createElement( parsed[1] ) ];
    }
    parsed = jQuery.buildFragment( [ data ], context, scripts );
    if ( scripts && scripts.length ) {
        jQuery( scripts ).remove();
    }
    return jQuery.merge( [], parsed.childNodes );
};
var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
var rhtml = /<|&#?\w+;/;
var rtagName = /<([\w:]+)/;
var rscriptType = /^$|\/(?:java|ecma)script/i;
var wrapMap = {
    option: [ 1, "<select multiple=‘multiple‘>", "</select>" ],
    thead: [ 1, "<table>", "</table>" ],
    col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
    tr: [ 2, "<table><tbody>", "</tbody></table>" ],
    td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
    _default: [ 0, "", "" ]
};
buildFragment: function( elems, context, scripts, selection ) {
        var elem, tmp, tag, wrap, contains, j,
            fragment = context.createDocumentFragment(),
            nodes = [],
            i = 0,
            l = elems.length;
        for ( ; i < l; i++ ) {
            elem = elems[ i ];
            if ( elem || elem === 0 ) {
                if ( jQuery.type( elem ) === "object" ) {
                    jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
                } else if ( !rhtml.test( elem ) ) {
                    nodes.push( context.createTextNode( elem ) );
                } else {
                    tmp = tmp || fragment.appendChild( context.createElement("div") );
                    tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
                    wrap = wrapMap[ tag ] || wrapMap._default;
                    tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
                    j = wrap[ 0 ];
                    while ( j-- ) {
                        tmp = tmp.lastChild;
                    }
                    jQuery.merge( nodes, tmp.childNodes );
                    tmp = fragment.firstChild;
                    tmp.textContent = "";
                }
            }
        }
        fragment.textContent = "";
        i = 0;
        while ( (elem = nodes[ i++ ]) ) {
            if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
                continue;
            }
            contains = jQuery.contains( elem.ownerDocument, elem );
            tmp = getAll( fragment.appendChild( elem ), "script" );
            if ( contains ) {
                setGlobalEval( tmp );
            }
            if ( scripts ) {
                j = 0;
                while ( (elem = tmp[ j++ ]) ) {
                    if ( rscriptType.test( elem.type || "" ) ) {
                        scripts.push( elem );
                    }
                }
            }
        }
        return fragment;
}
(function( window ) {
    var setDocument,
          docElem,
          preferredDoc = window.document,
          rnative = /^[^{]+\{\s*\[native \w/;
    function Sizzle( selector, context, results, seed ){
        ......
    }
    setDocument = Sizzle.setDocument = function( node ) {
        var hasCompare,
              doc = node ? node.ownerDocument || node : preferredDoc;
        hasCompare = rnative.test( docElem.compareDocumentPosition );
      contains = hasCompare || rnative.test( docElem.contains ) ?
        function( a, b ) {
            var adown = a.nodeType === 9 ? a.documentElement : a,
                bup = b && b.parentNode;
            return a === bup || !!( bup && bup.nodeType === 1 && (
                adown.contains ?
                    adown.contains( bup ) :
                    a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
            ));
        } :
        function( a, b ) {
            if ( b ) {
                while ( (b = b.parentNode) ) {
                    if ( b === a ) {
                        return true;
                    }
                }
            }
            return false;
        };
    }
    setDocument();
    ......
})(window)  

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。