1. 程式人生 > >jQuery原始碼解讀之init函式

jQuery原始碼解讀之init函式

jQuery的構造方法:

// 直接new了一個物件。同時根據jQuery.fn = jQuery.prototype,jQuery.fn相當於jQuery.prototype。

jQuery = function( selector, context ) {
        return new jQuery.fn.init( selector, context );
},

jQuery.fn.init方法:

init = jQuery.fn.init = function( selector, context, root ) {
    return jQuery.makeArray( selector, this );
};

init.prototype = jQuery.fn;

// init的原型指向了jQuery.fn,而jQuery.fn=jQuery.prototype即init.prototype=jQuery.prototype

// 根據js原型鏈的知識,我們通過init方法構造出來的物件,能訪問jQuery.prototype物件的方法。

// 當我們使用類似$(xxx)的時候,jquery為我們new了一個物件,並且這個物件的原型鏈指向jQuery.prototype,我們可以直接使用jQuery.prototype上的方法。

原始碼分析:

init = jQuery.fn.init = function( selector, context, root ) {
	var match, elem;

	// HANDLE: $(""), $(null), $(undefined), $(false)
		//判斷selector是否為空,是的話,直接返回this,也就是空的jquery物件。
	if ( !selector ) {
		return this;
	}

	//定義了root為rootjQuery,這裡的rootjQuery其實就是jQuery( document ),主要用於選擇器為空的時候,用rootjQuery上下文來代替空值,繼續下面的鏈式操作
	root = root || rootjQuery;

	//判斷selector是否為字串、是否為DOM型別、是否是一個function。

	// 如果selector為字串,通過正則判斷selector是不是html字串

	if ( typeof selector === "string" ) {
		if ( selector[ 0 ] === "<" &&
			selector[ selector.length - 1 ] === ">" &&
			selector.length >= 3 ) {

			//假設以<>開頭和結尾的字串是HTML並跳過正則表示式檢查
			match = [ null, selector, null ];

		} else {
			//通過正則判斷selector是不是html字串
			//rquickExpr用來匹配HTML標記和ID表示式
			match = rquickExpr.exec( selector );
		}

		//匹配html或確保沒有為#id指定上下文
		//selector為html字串
		if ( match && ( match[ 1 ] || !context ) ) {

			// HANDLE: $(html) -> $(array)
			//match[1]也就是HTML標記是否存在
			if ( match[ 1 ] ) {
				context = context instanceof jQuery ? context[ 0 ] : context;

				//jquery通過parseHTML(將html字串轉換為dom)和merge(把第二個陣列merge到第一個陣列)方法
				//將HTML標記轉化為由jQuery物件包裝的DOM元素,並返回
				jQuery.merge( this, jQuery.parseHTML(
					match[ 1 ],
					context && context.nodeType ? context.ownerDocument || context : document,
					true
				) );

				// HANDLE: $(html, props)
				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;

			// HANDLE: $(#id)
			//不存在html標記時直接通過match[2]也就是ID去取對應元素
			} else {
				elem = document.getElementById( match[ 2 ] );

				if ( elem ) {

					//將元素直接注入jQuery物件
					this[ 0 ] = elem;
					this.length = 1;
				}
				return this;
			}

		// HANDLE: $(expr, $(...))
		//如果不是html字串,判斷有沒有context
		//有context的話,使用context呼叫find方法(也就是sizzle)
		//沒有就是用document為context呼叫find。
		} else if ( !context || context.jquery ) {
			return ( context || root ).find( selector );

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

	// HANDLE: $(DOMElement)
	} else if ( selector.nodeType ) {
		this[ 0 ] = selector;
		this.length = 1;
		return this;

	// HANDLE: $(function)
	// document ready的縮寫
	} else if ( jQuery.isFunction( selector ) ) {
		return root.ready !== undefined ?
			root.ready( selector ) :

			//如果沒有準備就立即執行
			selector( jQuery );
	}

	// 處理成jquery陣列,這裡的makeArray對外是將一個類陣列物件轉換為真正的陣列物件,對內有個過載,就是處理成jquery陣列物件。
	return jQuery.makeArray( selector, this );
};

參考:

https://blog.csdn.net/m1213642578/article/details/52490423