jQuery源码解析之init

以下是对jquery-1.6.1.js中的init的解析,旨在分析ID选择器返回唯一一个匹配的元素(1),而多条件选择器返回的确是全部匹配的元素(2)。

(1)是ID选择器走的分支

(2)是多条件选择器走的分支

init: function( selector, context, rootjQuery ) {
		var match, elem, ret, doc;

		// 传入的selector为$(""), $(null), or $(undefined)
		if ( !selector ) {
			return this;
		}

		// 传入的selector是Dom元素,如document.getElementById("id")
        //注解1
		if ( selector.nodeType ) {
			this.context = this[0] = selector;
			this.length = 1;
			return this;
		}

		if ( selector === "body" && !context && document.body ) {
			this.context = document;
			this[0] = document.body;
			this.selector = selector;
			this.length = 1;
			return this;
		}

		// Handle HTML strings
		if ( typeof selector === "string" ) {
			// 传入"<tr>"
			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
				// Assume that strings that start and end with <> are HTML and skip the regex check
				match = [ null, selector, null ];

			} else {
				match = quickExpr.exec( selector );
			}

			// Verify a match, and that no context was specified for #id
			if ( match && (match[1] || !context) ) {
				// HANDLE: $(html) -> $(array)
				if ( match[1] ) {
					context = context instanceof jQuery ? context[0] : context;
					doc = (context ? context.ownerDocument || context : document);

					// If a single string is passed in and it's a single tag		
                    ret = rsingleTag.exec( selector ); // "<tr>" to "tr"		
					if ( ret ) {
						if ( jQuery.isPlainObject( context ) ) {
							selector = [ document.createElement( ret[1] ) ];
							jQuery.fn.attr.call( selector, context, true ); //TODO

						} else {
							selector = [ doc.createElement( ret[1] ) ]; //createElement: "tr" --> "<tr>"
						}

					} else {
					    //传入的selector中不包括Element,例如"fff"
						ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
						selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes; //return NodeList[<TextNode textContent="fff">]
					}

					return jQuery.merge( this, selector );

				// HANDLE: $("#id")
				} else {
                    //(1)是ID选择器走的分支
					elem = document.getElementById( match[2] );

					if ( elem && elem.parentNode ) {
						// Handle the case where IE and Opera return items
						// by name instead of ID
						if ( elem.id !== match[2] ) {
							return rootjQuery.find( selector );
						}

						// Otherwise, we inject the element directly into the jQuery object
                        //(1)是ID选择器走的分支
						this.length = 1;
						this[0] = elem;
					}

					this.context = document;
					this.selector = selector;
					return this;
				}

			// HANDLE: $(expr, $(...))
			} else if ( !context || context.jquery ) {
                //(2)是多条件选择器走的分支
				return (context || rootjQuery).find( selector );

			// HANDLE: $(expr, context)
			// (which is just equivalent to: $(context).find(expr)
			} else {
				return this.constructor( context ).find( selector );
			}

		// HANDLE: $(function)
		// Shortcut for document ready
		} else if ( jQuery.isFunction( selector ) ) {
			return rootjQuery.ready( selector );
		}

		if (selector.selector !== undefined) {
			this.selector = selector.selector;
			this.context = selector.context;
		}

		return jQuery.makeArray( selector, this );
	}

ID选择器和多条件选择器Demo:

$("#id");
$("#id1, #id2");

上面的例子在调用init创建就Query对象的时候,根本没有传递context,这里借用http://api.jquery.com/context/中的一句话来解释一下:Thevalueofthispropertyistypicallyequaltodocument,asthisisthedefaultcontextforjQueryobjectsifnoneissupplied.Thecontextmaydifferif,forexample,theobjectwascreatedbysearchingwithinan<iframe>orXMLdocument.

总结:(context||rootjQuery).find(selector);实际上是执行的document.find(selector);

注解1:关于这个分支的运用,举例如下:

var elem = document.getElementById("id_list[4521216583]");//返回的是Dom元素
//将Dom元素转为jquery对象的方法,也就是传入一个Dom元素,走注解1所在的分支
var $elem = $(elem);

//顺带解释一下,.value和.val()的区别
//value是Dom元素的属性
//val是jquery对象所有的
elem.value;
$elem.val();

相关推荐