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