天天看點

Sizzle源碼

首先使用原生語句查找,其次在context下找到所有節點元素,校驗元素是否比對選擇器,進行過濾,擷取到待查詢的元素。

過濾時分為兩種情形,針對選擇器是否帶:first()等位置關系僞類,若攜帶,setMatcher函數得到過濾函數,:first()僞類的校驗函數也通過引用對象的形式“濾除“未比對的節點;若不攜帶,elementMatcher得到校驗函數,其中層級關系如“#form > .input”,通過addCombinator函數包裝“#form“的校驗函數,根據選擇器">"待校驗節點和待過濾節elem的位置關系得到待校驗節點,同樣指派給elem(以便傳遞更上層的addCombinator包裝後的校驗函數)。該addCombinator包裝後的校驗函數和".input”校驗函數平級,通過elementMatcher函數實作自右向左的校驗,為傳遞elem的友善。

/*!
 * Sizzle CSS Selector Engine v2.3.0
 * https://sizzlejs.com/
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2016-01-04
 */
(function( window ) {

var i,
	support,
	Expr,
	getText,
	isXML,// 文檔根節點是否xml
	tokenize,
	compile,
	select,
	outermostContext,
	sortInput,
	hasDuplicate,// 用于判斷兩元素是否相同

	// Local document vars
	setDocument,
	document,
	docElem,
	documentIsHTML,// 文檔根節點是否html
	rbuggyQSA,// 存儲querySelectorAll方法不支援的查詢字元串
	rbuggyMatches,// 存儲matchesSelector方法不支援的查詢字元串
	matches,// 存儲各浏覽器的matchesSelector方法
	contains,

	// Instance-specific data
	expando="sizzle"+1*new Date(),// sizzle辨別
	preferredDoc=window.document,
	dirruns=0,
	done=0,
	// 緩存是否比對樣式的函數,[]屬性取出,()方法添加緩存
	classCache=createCache(),
	// 将選擇器通過正則轉化為對象形式(matched比對字元、type類型、matches拆分比對字元)存儲
	tokenCache=createCache(),
	// compilerCache存儲校驗函數
	compilerCache=createCache(),
	sortOrder=function(a,b){
		if ( a===b ){
			hasDuplicate=true;
		}
		return 0;
	},

	hasOwn=({}).hasOwnProperty,
	arr=[],
	pop=arr.pop,
	push_native=arr.push,
	push=arr.push,
	slice=arr.slice,
	indexOf=function(list,elem){
		var i=0,
			len=list.length;
		for ( ; i<len; i++ ){
			if ( list[i]===elem ){
				return i;
			}
		}
		return -1;
	},

	// 比對值為布爾型的
	booleans="checked|selected|async|autofocus|autoplay|controls|defer|disabled
		|hidden|ismap|loop|multiple|open|readonly|required|scoped",

	// 比對空格
	whitespace="[\\x20\\t\\r\\n\\f]",
	// 非擷取比對\.或A-Za-z0-9或unicode字元串
	identifier="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",

	// 比對[attrName='attrVal'],比對match[3|4|5]合并為check
	attributes="\\["+whitespace+"*("+identifier+")(?:"+whitespace+"*([*^$|!~]?=)"+whitespace+
		// 單引号包裹\.、非\',或雙引号包裹\.、非\",或identifier
		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+identifier+"))|)"+whitespace+
		"*\\]",

	pseudos=":("+identifier+")(?:\\(("+
		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|"+// 引号部分
		"((?:\\\\.|[^\\\\()[\\]]|"+attributes+")*)|"+// 使用js濾過部分
		".*"+// tokenize函數擷取")"前内容進行選擇,")"移除
		")\\)|)",

	// 比對空格
	rwhitespace=new RegExp(whitespace+"+","g"),
	// 比對首尾端的空格,(?:)非擷取比對
	rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),
	// 選擇器以空格、逗号起始,*比對0個或多個
	rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),
	// 選擇器以空格、>、+、~起始,*比對0個或多個
	rcombinators=new RegExp("^"+whitespace+"*([>+~]|"+whitespace+")"+whitespace+"*"),
	// 擷取屬性的值
	rattributeQuotes=new RegExp("="+whitespace+"*([^\\]'\"]*?)"+whitespace+"*\\]","g"),

	rpseudo=new RegExp(pseudos),
	ridentifier=new RegExp("^"+identifier+"$"),

	matchExpr={
		"ID":new RegExp("^#("+identifier+")"),
		"CLASS":new RegExp("^\\.("+identifier+")"),
		"TAG":new RegExp("^("+identifier+"|[*])"),
		"ATTR":new RegExp("^"+attributes),
		"PSEUDO":new RegExp("^"+pseudos),
		"CHILD":new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+whitespace+
			"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+
			"*(\\d+)|))"+whitespace+"*\\)|)","i"),// 參Expr.prefilter.CHILD
		"bool":new RegExp("^(?:"+booleans+")$","i"),
		// For use in libraries implementing .is()
		// We use this for POS matching in `select`
		"needsContext":new RegExp("^"+whitespace+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+
			whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)","i")// 比對eq(1)
	},

	rinputs=/^(?:input|select|textarea|button)$/i,// 比對input|select|textarea|button
	rheader=/^h\d$/i,// 比對h1、h2等

	rnative=/^[^{]+\{\s*\[native \w/,// 判斷是否浏覽器原生函數
	rquickExpr=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,// 比對id、tag、class選擇器

	rsibling=/[+~]/,

	// CSS escapes
	// 選擇器unicode轉義
	runescape=new RegExp("\\\\([\\da-f]{1,6}"+whitespace+"?|("+whitespace+")|.)","ig"),
	funescape=function(_,escaped,escapedWhitespace){
		var high="0x"+escaped-0x10000;
		
		return high!==high || escapedWhitespace ? escaped :
			high<0 ? String.fromCharCode(high+0x10000) :
			String.fromCharCode(high>>10 | 0xD800, high & 0x3FF | 0xDC00);
	},

	// CSS string/identifier serialization 轉義
	// https://drafts.csswg.org/cssom/#common-serializing-idioms
	rcssescape=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,
	fcssescape=function(ch,asCodePoint){
		if ( asCodePoint ){

			// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
			if ( ch==="\0" ){
				return "\uFFFD";
			}

			// Control characters and (dependent upon position) numbers get escaped as code points
			return ch.slice(0,-1)+"\\"+ch.charCodeAt(ch.length-1).toString(16)+" ";
		}

		// Other potentially-special ASCII characters get backslash-escaped
		return "\\"+ch;
	},

	// 使用者離開文檔時,重新調用setDocument函數設定document為sizzle.js所在文檔根節點
	unloadHandler=function(){
		setDocument();
	},

	disabledAncestor=addCombinator(
		function( elem ) {
			return elem.disabled === true;
		},
		{ dir: "parentNode", next: "legend" }
	);

// push方法拼接兩個數組
try{
	push.apply(
		(arr=slice.call(preferredDoc.childNodes)),
		preferredDoc.childNodes
	);

	arr[preferredDoc.childNodes.length].nodeType;
}catch(e){
	push={apply:arr.length ?

		function(target,els){
			push_native.apply(target,slice.call(els));
		} :
		function(target,els){
			var j=target.length,
				i=0;

			while ( (target[j++]=els[i++]) ){}
			target.length=j-1;
		}
	};
}

// 參數seed在matchs方法中使用,用以判斷元素
function Sizzle(selector,context,results,seed){
	var m, i, elem, nid, match, groups, newSelector,
		newContext=context && context.ownerDocument,
		nodeType=context ? context.nodeType : 9;

	results=results || [];

	// selector不是字元串,或context不是節點時,以results作為傳回值
	if ( typeof selector!=="string" || !selector || nodeType!==1 && nodeType!==9 && nodeType!==11 ){
		return results;
	}

	// 調用getElementBy["*"]或querySelectorAll方法快速查找元素
	if ( !seed ){

		if ( (context ? context.ownerDocument || context : preferredDoc)!==document ){
			setDocument(context);
		}
		context=context || document;

		if ( documentIsHTML ){
			// nodeType===11,DocumentFragment節點沒有getElementBy[*]方法
			if ( nodeType!==11 && (match=rquickExpr.exec(selector)) ){

				// ID選擇器快速查找
				if ( (m=match[1]) ){
					if ( nodeType===9 ){// 文檔節點
						if ( (elem=context.getElementById(m)) ){
							if ( elem.id === m ){
								results.push(elem);
								return results;
							}
						}else{
							return results;
						}
					}else{// 普通節點
						if ( newContext && (elem= newContext.getElementById(m)) &&
							contains(context,elem) && elem.id===m ){
							results.push(elem);
							return results;
						}
					}

				// Tag選擇器快速查找
				}else if(match[2]){
					push.apply(results,context.getElementsByTagName(selector));
					return results;

				// Class選擇器快速查找
				}else if( (m=match[3]) && support.getElementsByClassName &&
					context.getElementsByClassName ){
					push.apply(results,context.getElementsByClassName(m));
					return results;
				}
			}

			if ( support.qsa && !compilerCache[selector+" "] &&
				(!rbuggyQSA || !rbuggyQSA.test(selector)) ){

				if ( nodeType!==1 ){
					newContext=context;
					newSelector=selector;

				// Support: IE <=8 qSA方法将在context外查找元素,需重設selector,除了object節點
				}else if( context.nodeName.toLowerCase()!=="object" ){

					if ( (nid=context.getAttribute("id")) ){
						nid=nid.replace(rcssescape,fcssescape);
					}else{
						context.setAttribute("id",(nid=expando));
					}

					// 将selector通過正規表達式拆解成對象形式存儲到tokenCache中
					groups=tokenize(selector);
					i=groups.length;
					while ( i-- ){
						// toSelector擷取逗号前後分割的單一選擇器
						groups[i]="#"+nid+" "+toSelector(groups[i]);
					}
					newSelector=groups.join(",");

					// testContext(context.parentNode)傳回父節點
					newContext=rsibling.test(selector) && testContext(context.parentNode) ||
						context;
				}

				if ( newSelector ){
					try{
						push.apply(results,newContext.querySelectorAll(newSelector));
						return results;
					}catch( qsaError ){
					}finally{
						if ( nid===expando ){
							context.removeAttribute("id");
						}
					}
				}
			}
		}
	}

	// 不能調用getElementBy["*"]或querySelectorAll方法的,調用select函數查找
	return select(selector.replace(rtrim,"$1"),context,results,seed);
}

// 建立key-value緩存,存儲在建立緩存的cache函數裡,keys通過閉包維持存在
function createCache(){
	var keys=[];

	function cache(key,value){
		if ( keys.push(key+" ")>Expr.cacheLength ){// Expr.cacheLength預設50
			delete cache[keys.shift()];
		}
		return (cache[key+" "]=value);
	}
	return cache;
}

// 向傳參fn函數添加标記,以便sizzle進行移除、修改、查找處理
function markFunction(fn){
	fn[expando]=true;
	return fn;
}

// 建立fieldset元素,執行fn函數,用來實作浏覽器能力檢測
function assert(fn){
	var el=document.createElement("fieldset");

	try{
		return !!fn(el);
	}catch(e){
		return false;
	}finally{
		if ( el.parentNode ){
			el.parentNode.removeChild(el);
		}
		el=null;
	}
}

// 為Expr.attrHandle添加方法,針對浏覽器相容性問題,添加特殊的擷取屬性方法
function addHandle(attrs,handler){
	var arr=attrs.split("|"),
		i=arr.length;

	while ( i-- ){
		Expr.attrHandle[arr[i]]=handler;
	}
}

// 兩元素相鄰狀況,傳回-1時b為a後續的兄弟節點,1為其他情況
function siblingCheck(a,b){
	var cur=b && a,
		diff=cur && a.nodeType===1 && b.nodeType===1 && a.sourceIndex-b.sourceIndex;

	// 使用IE的sourceIndex方法判斷兩元素是否相鄰
	if ( diff ){
		return diff;
	}

	// Check if b follows a
	if ( cur ){
		while ( (cur=cur.nextSibling) ){
			if ( cur===b ){
				return -1;
			}
		}
	}

	return a ? 1 : -1;
}

// 建立:radio、:checkbox、:file、:password、:image僞類選擇器,傳回函數形式
function createInputPseudo(type){
	return function(elem){
		var name=elem.nodeName.toLowerCase();
		return name==="input" && elem.type===type;
	};
}

// 建立:submit、:reset僞類選擇器,傳回函數形式
function createButtonPseudo(type){
	return function(elem){
		var name=elem.nodeName.toLowerCase();
		return (name==="input" || name==="button") && elem.type===type;
	};
}

// 判斷表單元素是否可用
function createDisabledPseudo(disabled){
	// Known :disabled false positives:
	// IE: *[disabled]:not(button, input, select, textarea, optgroup, option, menuitem, fieldset)
	// not IE: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
	return function(elem){

		// Check form elements and option elements for explicit disabling
		return "label" in elem && elem.disabled===disabled ||
			"form" in elem && elem.disabled===disabled ||

			// Check non-disabled form elements for fieldset[disabled] ancestors
			"form" in elem && elem.disabled===false && (
				// Support: IE6-11+
				// Ancestry is covered for us
				elem.isDisabled===disabled ||

				// Otherwise, assume any non-<option> under fieldset[disabled] is disabled
				/* jshint -W018 */
				elem.isDisabled!==!disabled &&
					("label" in elem || !disabledAncestor(elem))!==disabled
			);
	};
}

// 由fn獲得比對元素的index值,再将seed中未比對的項置為false,matches添加比對的項
function createPositionalPseudo(fn){
	return markFunction(function(argument){
		argument=+argument;
		return markFunction(function(seed,matches){
			var j,
				matchIndexes=fn([],seed.length,argument),
				i=matchIndexes.length;

			// Match elements found at the specified indexes
			while ( i-- ){
				if ( seed[(j=matchIndexes[i])] ){
					seed[j]=!(matches[j]=seed[j]);
				}
			}
		});
	});
}

// context有getElementsByTagName方法,傳回context
function testContext(context){
	return context && typeof context.getElementsByTagName!=="undefined" && context;
}

// 浏覽器能力檢測
support=Sizzle.support={};

// 是否xml,通過判斷根節點是否html
isXML=Sizzle.isXML=function(elem){
	var documentElement=elem && (elem.ownerDocument || elem).documentElement;
	return documentElement ? documentElement.nodeName!=="HTML" : false;
};

// 傳回目前文檔根節點document,浏覽器能力檢測
setDocument=Sizzle.setDocument=function(node){
	var hasCompare, subWindow,
		doc=node ? node.ownerDocument || node : preferredDoc;

	// doc是目前的文檔根節點或者無效的節點
	if ( doc===document || doc.nodeType!==9 || !doc.documentElement ){
		return document;
	}

	document=doc;
	docElem=document.documentElement;
	documentIsHTML=!isXML(document);

	// Support: IE 9-11, Edge
	// 使用者離開文檔時,重新調用setDocument函數設定document為sizzle.js所在文檔根節點
	if ( preferredDoc!==document &&
		(subWindow=document.defaultView) && subWindow.top!==subWindow ){

		// Support: IE 11, Edge
		if ( subWindow.addEventListener ){
			subWindow.addEventListener("unload",unloadHandler,false);
		// Support: IE 9 - 10 only
		}else if( subWindow.attachEvent ){
			subWindow.attachEvent("onunload",unloadHandler);
		}
	}

	// 浏覽器能力getElementBy[*]檢測,Expr.find|filter["*"]方法改寫

	// Support: IE<8 校驗getAttribute方法能否擷取元素的屬性
	support.attributes=assert(function(el){
		el.className="i";
		return !el.getAttribute("className");
	});

	// 校驗getElementsByTagName("*")是否會傳回注釋節點
	support.getElementsByTagName=assert(function(el){
		el.appendChild(document.createComment(""));
		return !el.getElementsByTagName("*").length;
	});

	// Support: IE<9 函數體内含有native code
	support.getElementsByClassName=rnative.test(document.getElementsByClassName);

	// Support: IE<10 getElementById方法是否包含name屬性相同的元素,用getElementsByName校驗
	support.getById=assert(function(el){
		docElem.appendChild(el).id=expando;
		return !document.getElementsByName || !document.getElementsByName(expando).length;
	});

	if ( support.getById ){
		Expr.find["ID"]=function(id,context){
			if ( typeof context.getElementById!=="undefined" && documentIsHTML ){
				var m=context.getElementById(id);
				return m ? [m] : [];
			}
		};
		Expr.filter["ID"]=function(id){
			var attrId=id.replace(runescape,funescape);
			return function(elem){
				return elem.getAttribute("id")===attrId;
			};
		};
	}else{
		// Support: IE6/7 getElementById相容性問題
		delete Expr.find["ID"];

		Expr.filter["ID"]=function(id){
			var attrId=id.replace(runescape,funescape);
			return function(elem){
				var node=typeof elem.getAttributeNode!=="undefined" &&
					elem.getAttributeNode("id");
				return node && node.value===attrId;
			};
		};
	}

	Expr.find["TAG"]=support.getElementsByTagName ?
		function(tag,context){
			if ( typeof context.getElementsByTagName!=="undefined" ){
				return context.getElementsByTagName(tag);
			}else if( support.qsa ){
				return context.querySelectorAll(tag);
			}
		} :
		function(tag,context){
			var elem, tmp=[], i=0,
				results=context.getElementsByTagName(tag);

			if ( tag==="*" ){// 移除注釋節點
				while ( (elem=results[i++]) ){
					if ( elem.nodeType===1 ){
						tmp.push(elem);
					}
				}

				return tmp;
			}
			return results;
		};

	Expr.find["CLASS"]=support.getElementsByClassName && function(className,context){
		if ( typeof context.getElementsByClassName!=="undefined" && documentIsHTML ){
			return context.getElementsByClassName(className);
		}
	};

	// 浏覽器querySelectorAll、matchesSelector能力檢測

	// matchesSelector方法能力檢測,不支援的查詢字元串填入rbuggyMatches
	rbuggyMatches=[];
	// 各浏覽器querySelectorAll方法能力檢測,不支援的查詢字元串填入rbuggyQSA
	rbuggyQSA=[];

	if ( (support.qsa=rnative.test(document.querySelectorAll)) ){
		assert(function(el){
			docElem.appendChild(el).innerHTML="<a id='"+expando+"'></a>"+
				"<select id='"+expando+"-\r\\' msallowcapture=''>"+
				"<option selected=''></option></select>";

			// Support: IE8, Opera 11-12.16 屬性内容為空時理應找不到元素
			if ( el.querySelectorAll("[msallowcapture^='']").length ){
				rbuggyQSA.push("[*^$]="+whitespace+"*(?:''|\"\")");
			}

			// Support: IE8
			if ( !el.querySelectorAll("[selected]").length ){
				rbuggyQSA.push("\\["+whitespace+"*(?:value|"+booleans+")");
			}

			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
			if ( !el.querySelectorAll("[id~="+expando+"-]").length ){
				rbuggyQSA.push("~=");// ~=元素的屬性值中含有用空格分割的value
			}

			// IE8報錯
			if ( !el.querySelectorAll(":checked").length ){
				rbuggyQSA.push(":checked");
			}

			// Support: Safari 8+, iOS 8+
			if ( !el.querySelectorAll("a#"+expando+"+*").length ){
				rbuggyQSA.push(".#.+[+~]");
			}
		});

		assert(function(el){
			el.innerHTML="<a href='' disabled='disabled'></a>" +
				"<select disabled='disabled'><option/></select>";

			var input=document.createElement("input");
			input.setAttribute("type","hidden");
			el.appendChild(input).setAttribute("name","D");

			// Support: IE8
			if ( el.querySelectorAll("[name=d]").length ){
				rbuggyQSA.push("name"+whitespace+"*[*^$|!~]?=");
			}

			// FF 3.5 - 隐藏的元素狀态為enabled;IE8報錯
			if ( el.querySelectorAll(":enabled").length!==2 ){
				rbuggyQSA.push(":enabled",":disabled");
			}

			// Support: IE9-11+  狀态為disabled的元素其子節點為disabled時,将不包含該子節點
			docElem.appendChild(el).disabled=true;
			if ( el.querySelectorAll(":disabled").length!==2 ){
				rbuggyQSA.push(":enabled",":disabled");
			}

			// 無效的僞類本當報錯,不報錯的時候,rbuggyQSA添加",.*:"
			el.querySelectorAll("*,:x");
			rbuggyQSA.push(",.*:");
		});
	}

	if ( (support.matchesSelector=rnative.test( (matches=docElem.matches ||
		docElem.webkitMatchesSelector || docElem.mozMatchesSelector ||
		docElem.oMatchesSelector || docElem.msMatchesSelector) )) ){

		assert(function( el ) {
			// IE 9 未插入文檔的節點是否适用matchesSelector
			support.disconnectedMatch=matches.call(el,"*");

			matches.call(el,"[s!='']:x");
			rbuggyMatches.push("!=",pseudos);
		});
	}

	rbuggyQSA=rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
	rbuggyMatches=rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );

	// 判斷a元素是否包含b元素
	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) :
				// compareDocumentPosition方法判斷元素的相對位置
				// a & 16 按位與,當a大于等于16為16,其他為0
				a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
			));
		} :
		function(a,b){
			if (b){
				while ( (b=b.parentNode) ){
					if ( b===a ){
						return true;
					}
				}
			}
			return false;
		};

	// 判斷a、b元素的位置關系
	sortOrder=hasCompare ?
	function(a,b){
		if ( a===b ){
			hasDuplicate=true;
			return 0;
		}

		// 其中一個有compareDocumentPosition方法,一個沒有
		var compare=!a.compareDocumentPosition-!b.compareDocumentPosition;
		if ( compare ){
			return compare;
		}

		compare=(a.ownerDocument || a)===(b.ownerDocument || b) ?
			a.compareDocumentPosition(b) : 1;// 不在同一個文檔

		// 不相關的節點,a在目前文檔中傳回-1,b在目前文檔中傳回1
		if ( compare & 1 ||
			(!support.sortDetached && b.compareDocumentPosition(a)===compare) ){

			if ( a===document || a.ownerDocument===preferredDoc && contains(preferredDoc,a) ){
				return -1;
			}
			if ( b===document || b.ownerDocument===preferredDoc && contains(preferredDoc,b) ){
				return 1;
			}

			// Maintain original order
			return sortInput ? ( indexOf(sortInput,a)-indexOf(sortInput,b) ) : 0;
		}

		return compare & 4 ? -1 : 1;
	} :
	function(a,b){
		if ( a===b ){
			hasDuplicate=true;
			return 0;
		}

		var cur,
			i=0,
			aup=a.parentNode,
			bup=b.parentNode,
			ap=[a],
			bp=[b];

		// Parentless nodes are either documents or disconnected
		if ( !aup || !bup ){
			return a===document ? -1 :
				b===document ? 1 :
				aup ? -1 :
				bup ? 1 :
				sortInput ?
				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
				0;

		// If the nodes are siblings, we can do a quick check
		}else if( aup===bup ){
			return siblingCheck(a,b);
		}

		// Otherwise we need full lists of their ancestors for comparison
		cur = a;
		while ( (cur = cur.parentNode) ) {
			ap.unshift( cur );
		}
		cur = b;
		while ( (cur = cur.parentNode) ) {
			bp.unshift( cur );
		}

		// Walk down the tree looking for a discrepancy
		while ( ap[i] === bp[i] ) {
			i++;
		}

		return i ?
			// Do a sibling check if the nodes have a common ancestor
			siblingCheck( ap[i], bp[i] ) :

			// Otherwise nodes in our document sort first
			ap[i]===preferredDoc ? -1 :
			bp[i]===preferredDoc ? 1 :
			0;
	};

	return document;
};

// 濾除elements中不滿足expr的元素
Sizzle.matches=function(expr,elements){
	return Sizzle(expr,null,null,elements);
};

// 檢查elem是否expr選擇器,原生語句matchesSelector()優先
Sizzle.matchesSelector=function(elem,expr){
	if ( (elem.ownerDocument || elem)!==document ){
		setDocument(elem);
	}

	expr=expr.replace(rattributeQuotes,"='$1']");

	if ( support.matchesSelector && documentIsHTML &&
		!compilerCache[expr+" "] && ( !rbuggyMatches || !rbuggyMatches.test(expr) ) &&
		( !rbuggyQSA || !rbuggyQSA.test(expr) ) ){

		try {
			var ret=matches.call(elem,expr);

			// IE 9's matchesSelector returns false on disconnected nodes
			if ( ret || support.disconnectedMatch ||
					// As well, disconnected nodes are said to be in a document
					// fragment in IE 9
					elem.document && elem.document.nodeType!==11 ) {
				return ret;
			}
		}catch(e){}
	}

	return Sizzle(expr,document,null,[elem]).length>0;
};

// 判斷是否包含
Sizzle.contains=function(context,elem){
	if ( (context.ownerDocument || context)!==document ){
		setDocument(context);
	}
	return contains(context,elem);
};

// 有相容性問題的個别屬性通過Expr.attrHandle[name.toLowerCase()]方法擷取
// 目前浏覽器支援getAttribute方法或者xml文檔的時候,通過getAttribute方法擷取
// 其他通過getAttributeNode(name).specified擷取屬性值
Sizzle.attr=function(elem,name){
	if ( (elem.ownerDocument || elem)!==document ){
		setDocument(elem);
	}

	var fn=Expr.attrHandle[name.toLowerCase()],
		val=fn && hasOwn.call(Expr.attrHandle,name.toLowerCase()) ?
			fn(elem,name,!documentIsHTML) : undefined;

	return val!==undefined ?
		val :
		support.attributes || !documentIsHTML ?
			elem.getAttribute(name) :
			(val=elem.getAttributeNode(name)) && val.specified ? val.value : null;
};

// unicode轉義
Sizzle.escape=function(sel){
	return (sel+"").replace(rcssescape,fcssescape);
};

// 報錯
Sizzle.error=function(msg){
	throw new Error("Syntax error, unrecognized expression: "+msg);
};

// support.detectDuplicates為否時去重,為真時保留重複項
Sizzle.uniqueSort=function(results){
	var elem, duplicates=[], j=0, i=0;

	hasDuplicate=!support.detectDuplicates;
	sortInput=!support.sortStable && results.slice(0);
	results.sort(sortOrder);

	if ( hasDuplicate ){
		// 比對前後兩個數組項是否相同,相同記錄前一項的index,splice方法移除該項
		while ( (elem=results[i++]) ){
			if ( elem===results[i] ){
				j=duplicates.push(i);
			}
		}
		while ( j-- ){
			results.splice(duplicates[j],1);
		}
	}

	sortInput=null;

	return results;
};

// 調用textContent屬性或者拼接字元串的方式擷取節點及子節點的文本内容
getText=Sizzle.getText=function(elem){
	var node, ret="", i=0, nodeType=elem.nodeType;

	if ( !nodeType ){
		while ( (node=elem[i++]) ){
			ret+=getText(node);
		}
	}else if( nodeType===1 || nodeType===9 || nodeType===11 ){
		if ( typeof elem.textContent==="string" ){
			return elem.textContent;
		}else{
			for( elem=elem.firstChild; elem; elem=elem.nextSibling ){
				ret+=getText(elem);
			}
		}
	}else if( nodeType===3 || nodeType===4 ){
		return elem.nodeValue;
	}

	return ret;
};

Expr=Sizzle.selectors={

	cacheLength:50,// 緩存預設長度
	createPseudo: markFunction,// fn添加屬性,以便查找及管理
	match:matchExpr,// 正規表達式
	attrHandle:{},// 針對浏覽器相容性問題,添加特殊的擷取屬性方法,如value、disabled等

	find:{},

	// dir待校驗元素與自右向左查詢元素的相對關系,first為真值,嚴格校驗模式
	// 如">",須嚴格確定父子關系
	relative:{
		">":{dir:"parentNode",first:true},
		" ":{dir:"parentNode"},
		"+":{dir:"previousSibling",first:true},
		"~":{dir:"previousSibling"}
	},

	// 處理比對的正則數組,同時将正規表達式不完善的地方補全
	preFilter:{
		"ATTR":function(match){
			// match[1] Expr.filter.ATTR中參數name
			// match[2] Expr.filter.ATTR中參數operator
			// match[3] Expr.filter.ATTR中參數check
			match[1]=match[1].replace(runescape,funescape);

			match[3]=(match[3] || match[4] || match[5] || "").replace(runescape,funescape);

			if ( match[2]==="~=" ){
				match[3]=" "+match[3]+" ";
			}

			return match.slice(0,4);
		},
		"CHILD":function(match){
			// match[1] Expr.filter.ChILD中參數type 如nth
			// match[2] Expr.filter.ChILD中參數what 如child
			// match[3] Expr.filter.ChILD中參數argument 如3n+2
			// match[4] Expr.filter.ChILD中參數first 如3
			// match[5] Expr.filter.ChILD中參數last 如2
			/* matches from matchExpr["CHILD"]
				1 type (only|nth|...)
				2 what (child|of-type)
				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 如+3n-2
				4 xn-component of xn+y argument ([+-]?\d*n|) 如+3n
				5 sign of xn-component 如+
				6 x of xn-component 如3
				7 sign of y-component 如-
				8 y of y-component 如2
			*/
			match[1]=match[1].toLowerCase();

			if ( match[1].slice(0,3)==="nth" ){
				if ( !match[3] ){
					Sizzle.error(match[0]);
				}

				match[4]=+( match[4] ? match[5]+(match[6] || 1) : 2*( match[3]==="even" || match[3]==="odd" ) );
				match[5]=+( (match[7]+match[8]) || match[3]==="odd" );

			}else if( match[3] ){
				Sizzle.error(match[0]);
			}

			return match;
		},
		"PSEUDO":function(match){
			// match[1] Expr.filter.PSEUDO中參數pesudo,Expr.pseudos中方法名 如not
			// match[2] Expr.filter.PSEUDO中參數argument,Expr.pseudos["*"]方法的參數 如".btn"
			/* matches from matchExpr["PSEUDO"] not(".btn")
				1 pesudo (not|eq|gt|hidden)
				2 argument ('*'|"*"|\d|...) 如".btn"
				3 quotes ('*'|"*") 如".btn"
				4 single-quote ('')
				5 double-quote ("") 如".btn"
				6 使用js語句進行過濾,不比對
			*/
			var excess,
				unquoted=!match[6] && match[2];

			if ( matchExpr["CHILD"].test(match[0]) ){// 作為child選擇器處理
				return null;
			}

			if ( match[3] ){
				match[2]=match[4] || match[5] || "";
			}else if( unquoted && rpseudo.test(unquoted) &&
				(excess=tokenize(unquoted,true)) &&
				(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length) ){

				match[0]=match[0].slice(0,excess);// 移除")"後字元串
				match[2]=unquoted.slice(0,excess);
			}

			return match.slice(0,3);
		}
	},

	// 比對tag、class、attr、child、pseudo的方法,驗證元素是否比對,傳回值為校驗函數
	filter:{
		"TAG":function(nodeNameSelector){
			var nodeName=nodeNameSelector.replace(runescape,funescape).toLowerCase();
			return nodeNameSelector==="*" ?
				function(){return true;} :
				function(elem){
					return elem.nodeName && elem.nodeName.toLowerCase()===nodeName;
				};
		},
		"CLASS":function(className){
			var pattern=classCache[className+" "];

			return pattern ||
				(pattern=new RegExp("(^|"+whitespace+ ")"+className+"("+whitespace+"|$)")) &&
				classCache(className,function(elem){
					return pattern.test( typeof elem.className==="string" && elem.className || typeof elem.getAttribute!=="undefined" && elem.getAttribute("class") || "" );
				});
		},
		"ATTR":function(name,operator,check){// name屬性名,operator操作符,check屬性值
			return function(elem){
				var result=Sizzle.attr(elem,name);

				if ( result==null ){
					return operator==="!=";
				}
				if ( !operator ){
					return true;
				}

				result+="";

				return operator==="=" ? result===check :
					operator==="!=" ? result!==check :
					operator==="^=" ? check && result.indexOf(check)===0 :// 某值為首項
					operator==="*=" ? check && result.indexOf(check)>-1 :// 含某值
					operator==="$=" ? check && result.slice(-check.length)===check :// 以某值結尾
					operator==="~=" ? (" "+result.replace(rwhitespace," ")+" ").indexOf(check)>-1 :// 以空格分割的某值
					operator==="|=" ? result===check || result.slice(0,check.length+1)===check+"-" :// 某值在起始處,以連字元起始
					false;
			};
		},
		// nth-child(3n+2) type為nth,what為child,argument為3n+2,first為3,last為2
		"CHILD":function(type,what,argument,first,last){
			var simple=type.slice(0,3)!=="nth",
				forward=type.slice(-4)!=="last",
				ofType=what==="of-type";

			return first===1 && last===0 ? 
				// :nth-child(1)、:nth-type-of(1)
				function( elem ){// 比對首個元素
					return !!elem.parentNode;
				} :
				function(elem,context,xml){
					var cache, uniqueCache, outerCache, node, nodeIndex, start,
						dir=simple!==forward ? "nextSibling" : "previousSibling",
						parent=elem.parentNode,
						name=ofType && elem.nodeName.toLowerCase(),
						useCache=!xml && !ofType,// 非xml文檔,nth-child選擇器,緩存
						diff=false;

					if ( parent ){
						// :(first|last|only)-(child|of-type)
						if ( simple ){
							// simple限制為真值,dir随last-child變為nextSibling
							// first-child之前有元素傳回false,last-child判斷其後有無元素
							while ( dir ){
								node=elem;
								while ( (node=node[dir]) ){
									if ( ofType ? node.nodeName.toLowerCase()===name :
										node.nodeType===1 ){
										return false;
									}
								}
								// only-child時,dir由previousSibling反轉為nextSibling
								start=dir=type==="only" && !start && "nextSibling";
							}
							return true;
						}

						start=[forward ? parent.firstChild : parent.lastChild];

						// 不是xml文檔、nth-child選擇器條件下使用緩存
						if ( forward && useCache ){
							node=parent;
							outerCache=node[expando] || (node[expando]={});

							// uniqueCache緩存目前元素的序号diff,nodeIndex包含其他節點元素形式
							uniqueCache=outerCache[node.uniqueID] ||
								(outerCache[node.uniqueID]={});

							cache=uniqueCache[type] || [];
							nodeIndex=cache[0]===dirruns && cache[1];
							diff=nodeIndex && cache[ 2 ];
							node=nodeIndex && parent.childNodes[nodeIndex];

							while ( (node=++nodeIndex && node && node[dir] ||
								// 沒有緩存時初始設定diff=nodeIndex=0,node=parent.firstChild
								(diff=nodeIndex=0) || start.pop()) ){
								if ( node.nodeType===1 && ++diff && node===elem ){
									uniqueCache[type]=[dirruns,nodeIndex,diff];
									break;
								}
							}

						}else{
							if ( useCache ){
								node=elem;
								outerCache=node[expando] || (node[expando]={});

								uniqueCache=outerCache[node.uniqueID] ||
									(outerCache[node.uniqueID]={});

								cache=uniqueCache[type] || [];
								nodeIndex=cache[0]===dirruns && cache[1];
								diff=nodeIndex;
							}

							// xml :nth-child(...)
							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
							if ( diff===false ){
								while ( (node=++nodeIndex && node && node[dir] ||
									(diff=nodeIndex=0) || start.pop()) ){

									if ( ( ofType ?
										node.nodeName.toLowerCase()===name :// 标簽相同的元素
										node.nodeType===1 ) && ++diff ){

										if ( useCache ){
											outerCache=node[expando] || (node[expando]={});

											uniqueCache=outerCache[node.uniqueID] ||
												(outerCache[node.uniqueID]={});

											uniqueCache[type]=[dirruns,diff];
										}

										if ( node===elem ){
											break;
										}
									}
								}
							}
						}

						diff-=last;// 節點的序号diff
						return diff===first || (diff%first===0 && diff/first>=0);
					}
				};
		},

		"PSEUDO":function(pseudo,argument){
			var args,
				// 擷取僞類校驗函數,Expr.pseudos優先級高于Expr.setFilters
				// Expr.setFilters的原型為Expr.pseudos
				fn=Expr.pseudos[pseudo] || Expr.setFilters[pseudo.toLowerCase()] ||
					Sizzle.error("unsupported pseudo: "+pseudo);

			// pesudo如not、has等通過createPseudo建立校驗函數fn、或first等通過createPositionalPseudo建立
			// 校驗函數需要配置參數方可用于校驗元素
			if ( fn[expando] ){
				return fn(argument);
			}

			// But maintain support for old signatures
			// jquery原先的版本用length代替expando實作其功能???
			if ( fn.length>1 ) {
				args=[pseudo,pseudo,"",argument];
				// pseudo為Expr.setFilters執行個體自有的方法名,參數為待過濾元素和argument
				// 使用引用對象形式過濾,而不是傳回過濾結果
				// 傳參seed待過濾元素,函數執行完成seed中比對項設為false
				return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase()) ?
					markFunction(function(seed,matches){
						var idx,
							matched=fn(seed,argument),
							i=matched.length;
						while( i-- ){
							idx=indexOf(seed,matched[i]);
							seed[idx]=!(matches[idx]=matched[i]);
						}
					}) :
					function(elem){
						return fn(elem,0,args);
					};
			}

			return fn;
		}
	},

	// 是否比對僞類選擇器函數
	pseudos:{
		// :not('.classname')校驗元素不是.classname元素
		"not":markFunction(function(selector){
			var input=[],
				results=[],
				// 通過compile擷取:not()内選擇器的校驗函數
				matcher=compile(selector.replace(rtrim,"$1"));

			return matcher[expando] ? // :not()内選擇器為:first等
				markFunction(function(seed,matches,context,xml){
					var elem,
						unmatched=matcher(seed,null,xml,[]),
						i=seed.length;

					while ( i-- ){
						if ( (elem=unmatched[i]) ){
							seed[i]=!(matches[i]=elem);// 比對matcher的設為否值
						}
					}
				}) :
				function(elem,context,xml){
					input[0]=elem;
					matcher(input,null,xml,results);
					input[0]=null;
					return !results.pop();
				};
		}),

		// 使用elementMatchers普通校驗函數,傳回布爾值
		// 首先由Expr.filter.PESUDO方法獲得selector參數,再使用傳回函數校驗elem
		"has":markFunction(function(selector){
			return function(elem){
				return Sizzle(selector,elem).length>0;
			};
		}),
		// 是否包含給定文本
		"contains":markFunction(function(text){
			text=text.replace(runescape,funescape);
			return function(elem){
				return ( elem.textContent || elem.innerText || getText(elem) ).indexOf(text)>-1;
			};
		}),
		// :lang(en)校驗<div />或<div />
		"lang":markFunction(function(lang){
			if ( !ridentifier.test(lang || "") ){
				Sizzle.error("unsupported lang: "+lang);
			}
			lang=lang.replace(runescape,funescape).toLowerCase();
			return function(elem){
				var elemLang;
				do {
					if ( (elemLang=documentIsHTML ?
						elem.lang :
						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ){

						elemLang=elemLang.toLowerCase();
						return elem| elemLang.indexOf(lang+"-")===0;
					}
				} while ( (elem=elem.parentNode) && elem.nodeType===1 );
				return false;
			};
		}),

		// 使用elementMatchers普通校驗函數,傳回布爾值
		// 以目前頁面hash為id屬性的節點
		"target":function(elem){
			var hash=window.location && window.location.hash;//  http://example.com/#foo情形為foo
			return hash && hash.slice(1)===elem.id;
		},
		// 根節點
		"root":function(elem){
			return elem===docElem;
		},

		"focus":function(elem){
			return elem===document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
		},
		"enabled":createDisabledPseudo(false),
		"disabled":createDisabledPseudo(true),
		// 選中的option或radio、checkbox
		"checked":function(elem){
			// In CSS3, :checked should return both checked and selected elements
			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
			var nodeName=elem.nodeName.toLowerCase();
			return (nodeName==="input" && !!elem.checked) || (nodeName==="option" && !!elem.selected);
		},
		// 選中的option
		"selected":function(elem){
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			if ( elem.parentNode ) {
				elem.parentNode.selectedIndex;
			}

			return elem.selected===true;
		},

		// 元素是否沒有子節點
		"empty":function(elem){
			// http://www.w3.org/TR/selectors/#empty-pseudo
			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
			//   but not by others (comment: 8; processing instruction: 7; etc.)
			// nodeType < 6 works because attributes (2) do not appear as children
			for ( elem=elem.firstChild; elem; elem=elem.nextSibling ){
				if ( elem.nodeType<6 ){
					return false;
				}
			}
			return true;
		},
		// 作為父節點
		"parent":function(elem){
			return !Expr.pseudos["empty"](elem);
		},

		// h1、h2等
		"header":function(elem){
			return rheader.test(elem.nodeName);
		},

		// 表單元素select、input、button、textarea
		"input":function(elem){
			return rinputs.test(elem.nodeName);
		},
		"button":function(elem){
			var name=elem.nodeName.toLowerCase();
			return name==="input" && elem.type==="button" || name==="button";
		},
		// 輸入框
		"text":function(elem){
			var attr;
			return elem.nodeName.toLowerCase()==="input" &&
				elem.type==="text" &&

				// Support: IE<8
				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
				( (attr=elem.getAttribute("type"))==null || attr.toLowerCase()==="text" );
		},

		// 比對index值為0的元素,setMatchers特殊校驗函數中傳入待過濾元素,index=0的滿足條件
		"first":createPositionalPseudo(function(){
			return [0];
		}),
		"last":createPositionalPseudo(function(matchIndexes,length){
			return [length-1];
		}),
		"eq":createPositionalPseudo(function(matchIndexes,length,argument){
			return [argument<0 ? argument+length : argument];
		}),
		// index為偶數的元素
		"even":createPositionalPseudo(function(matchIndexes,length){
			var i=0;
			for ( ; i<length; i+=2 ){
				matchIndexes.push(i);
			}
			return matchIndexes;
		}),
		"odd":createPositionalPseudo(function(matchIndexes,length){
			var i = 1;
			for ( ; i<length; i+=2 ){
				matchIndexes.push(i);
			}
			return matchIndexes;
		}),
		// :lt(3) index值小于3的元素
		"lt":createPositionalPseudo(function(matchIndexes,length,argument){
			var i = argument < 0 ? argument + length : argument;
			for ( ; --i >= 0; ) {
				matchIndexes.push( i );
			}
			return matchIndexes;
		}),
		"gt":createPositionalPseudo(function(matchIndexes,length,argument){
			var i=argument<0 ? argument+length : argument;
			for ( ; ++i<length; ) {
				matchIndexes.push(i);
			}
			return matchIndexes;
		})
	}
};

Expr.pseudos["nth"]=Expr.pseudos["eq"];

// 建立radio、checkbox、file、password、image僞類選擇器
for ( i in {radio:true, checkbox:true, file:true, password:true, image:true} ){
	Expr.pseudos[i]=createInputPseudo(i);
}
// 建立:submit、:reset僞類選擇器
for ( i in {submit:true, reset:true} ){
	Expr.pseudos[i]=createButtonPseudo(i);
}

// 對外提供添加Expr.pseudos的接口,Expr.pseudos優先級高于Expr.setFilters
function setFilters(){}
setFilters.prototype=Expr.filters=Expr.pseudos;
Expr.setFilters=new setFilters();

// parseOnly為真輸出未比對字元串的長度,否則報錯或者添加緩存tokenCache
// .className,[attr] 将被拆解為兩個tokens存儲在groups中,表示兩個選擇器
// .className > [attr] 将被拆解為一個tokens存儲在groups中
tokenize=Sizzle.tokenize=function(selector,parseOnly){
	var matched, match, tokens, type,
		soFar, groups, preFilters,
		cached=tokenCache[selector+" "];

	if ( cached ){
		return parseOnly ? 0 : cached.slice(0);
	}

	soFar=selector;
	groups=[];
	preFilters=Expr.preFilter;// 處理比對的正則字元串

	while ( soFar ){
		// 選擇器以空格+逗号起始,移除該空格+逗号
		if ( !matched || (match=rcomma.exec(soFar)) ){
			if ( match ){
				soFar=soFar.slice(match[0].length) || soFar;
			}
			groups.push((tokens=[]));
		}

		matched=false;

		// 選擇器以空格、>、+、~起始,*比對0個或多個
		// tokens中value正則比對的數組,type類型如>或+或~
		if ( (match=rcombinators.exec(soFar)) ){
			matched=match.shift();
			tokens.push({
				value:matched,
				type:match[0].replace(rtrim," ")
			});
			soFar=soFar.slice(matched.length);
		}

		for ( type in Expr.filter ){// type為tag、class、attr、child或pseudo
			if ( (match=matchExpr[type].exec(soFar)) && (!preFilters[type] ||
				(match=preFilters[type](match))) ){
				matched=match.shift();
				tokens.push({
					value:matched,// 比對的完整字元串
					type:type,// 類型如tag、class、attr、child或pseudo
					matches:match// 比對字元串拆分的數組,如Attr将被拆分為name、operator、check
				});
				soFar=soFar.slice(matched.length);
			}
		}

		if ( !matched ){
			break;
		}
	}

	// parseOnly為真時,傳回未比對字元串的長度,否則報錯或者tokenCache添加處理後的比對内容tokens
	return parseOnly ? soFar.length :
		soFar ? Sizzle.error(selector) : tokenCache(selector,groups).slice(0);
};

// 擷取逗号前後分割的單一選擇器
function toSelector(tokens){
	var i=0,
		len=tokens.length,
		selector="";
	for ( ; i<len; i++ ){
		selector+=tokens[i].value;
	}
	return selector;
}

// 包裝matcher,傳回校驗函數,用以校驗特定的elem,按情況啟動循環及緩存
// 		緩存放置在待校驗元素的父節點上
// combinator配置待檢測元素和elem的位置關系,以及檢測标準,嚴格父子臨近關系或其他
function addCombinator(matcher,combinator,base){
	var dir=combinator.dir,
		skip=combinator.next,// 跳過校驗的元素nodeName
		key=skip || dir,
		checkNonElements=base && key==="parentNode",
		doneName=done++;

	// combinator.first為真確定待校驗元素和elem嚴格父子或鄰近節點關系
	// 傳回matcher執行結果,中斷循環;否則周遊元素執行matcher,比對時跳出循環
	return combinator.first ?
		function(elem,context,xml){
			while ( (elem=elem[dir]) ){
				if ( elem.nodeType===1 || checkNonElements ){
					return matcher(elem,context,xml);
				}
			}
		} :
		function(elem,context,xml){
			var oldCache, uniqueCache, outerCache,
				newCache=[dirruns,doneName];

			// 隻要有祖先節點和兄弟節點滿足校驗條件
			if ( xml ){
				while ( (elem=elem[dir]) ){
					if ( elem.nodeType===1 || checkNonElements ){
						if ( matcher(elem,context,xml) ){
							return true;
						}
					}
				}
			}else{
				while ( (elem=elem[dir]) ){
					if ( elem.nodeType===1 || checkNonElements ){
						outerCache=elem[expando] || (elem[expando]={});

						// Support: IE <9 only
						// Defend against cloned attroperties (jQuery gh-1709)
						uniqueCache=outerCache[elem.uniqueID] || (outerCache[elem.uniqueID]={});

						if ( skip && skip===elem.nodeName.toLowerCase() ){
							elem=elem[dir] || elem;
						}else if( (oldCache=uniqueCache[key]) &&
							oldCache[0]===dirruns && oldCache[1]===doneName ){

							return (newCache[2]=oldCache[2]);
						}else{
							uniqueCache[key]=newCache;

							if ( (newCache[2]=matcher(elem,context,xml)) ){
								return true;
							}
						}
					}
				}
			}
		};
}

// 傳回校驗函數,elem比對matchers中所有校驗器的驗證規則,傳回真,否則為否
// 選擇器自右向左校驗
function elementMatcher(matchers){
	return matchers.length>1 ?
		function(elem,context,xml){
			var i=matchers.length;
			while ( i-- ){
				if ( !matchers[i](elem,context,xml) ){
					return false;
				}
			}
			return true;
		} :
		matchers[0];
}

// 多個上下文contexts中查找selector元素
function multipleContexts(selector,contexts,results){
	var i=0,
		len=contexts.length;
	for ( ; i<len; i++ ){
		Sizzle(selector,contexts[i],results);
	}
	return results;
}

// 校驗函數filter過濾元素unmatched,過濾結果作為傳回值,map存儲比對的序号
// 除了filter函數過濾外,unmatched需保證為真值
function condense(unmatched,map,filter,context,xml){
	var elem,
		newUnmatched=[],
		i=0,
		len=unmatched.length,
		mapped=map!=null;

	for ( ; i<len; i++ ){
		if ( (elem=unmatched[i]) ){
			if ( !filter || filter(elem,context,xml) ){
				newUnmatched.push(elem);
				if ( mapped ){
					map.push(i);
				}
			}
		}
	}

	return newUnmatched;
}

// 以:not選擇器為例,preFilter為:not之前選擇器的校驗函數,
// selector為:not之前選擇器完全值,後加"*"或""
// matcher為:not選擇器的校驗函數
// postFilter為:not之後的校驗函數,"+"等操作符前
// postFinder為:not之後的校驗函數,"+"等操作符後
// postSelector為選擇器完全值
// 建立特殊校驗函數并傳回,用于查找:not、:first等選擇器
function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){
	if ( postFilter && !postFilter[expando] ){
		postFilter=setMatcher(postFilter);
	}
	if ( postFinder && !postFinder[expando] ){
		postFinder=setMatcher(postFinder,postSelector);
	}
	return markFunction(function(seed,results,context,xml){
		var temp, i, elem,
			preMap=[],// :not前選擇器校驗函數比對結果的序号集	
			postMap=[],// :not選擇器校驗函數比對結果的序号集	
			preexisting=results.length,

			// 無seed情況下,調用multipleContexts找到比對:not前選擇器的元素
			elems=seed || multipleContexts(selector||"*",context.nodeType?[context]:context,[]),

			// condense(unmatched,map,filter,context,xml)校驗函數filter過濾元素unmatched,過濾結果作為傳回值,map存儲比對的序号
			// 使用preFilter過濾elems元素,過濾後的結果集指派給matcherIn,preMap過濾結果的序号集
			matcherIn=preFilter && (seed || !selector) ?
				condense(elems,preMap,preFilter,context,xml) : elems,

			// 無matcher,matcherOut指派為matcherIn
			matcherOut=matcher ?
				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?

					// ...intermediate processing is necessary
					[] :

					// ...otherwise use results directly
					results :
				matcherIn;

		// 特殊Expr.filter方法過濾matcherIn,過濾結果寫入matcherOut
		// matcher設定的标準,matcherIn中比對項記為false,matcherOut帶序号包含比對的節點
		if ( matcher ){
			matcher(matcherIn,matcherOut,context,xml);
		}

		// postFilter也是特殊過濾器
		if ( postFilter ) {
			temp=condense(matcherOut,postMap);// 将matcherOut拷貝給temp,postMap過濾結果的序号集
			postFilter(temp,[],context,xml);// 将temp比對項設為否值

			i=temp.length;
			while ( i-- ){
				if ( (elem=temp[i]) ){
					// 将matcherOut中不比對項設為否值
					matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem);
				}
			}
		}

		// matcherOut之前校驗函數的結果,未比對的記為false,比對的為節點元素,
		// 有seed,傳回結果results不比對的元素記為否值
		// 無seed,if語句清洗值為false的matcherOut數組項,results傳回比對元素
		if ( seed ){
			if ( postFinder || preFilter ){
				if ( postFinder ){
					temp=[];
					i=matcherOut.length;
					while ( i-- ){
						if ( (elem=matcherOut[i]) ){
							temp.push( (matcherIn[i]=elem) );// 比對的元素
						}
					}
					// setMatcher(postFinder,postSelector)查詢temp下所有元素節點并過濾
					postFinder(null,(matcherOut=[]),temp,xml);
				}

				i=matcherOut.length;
				while ( i-- ){
					if ( (elem=matcherOut[i]) &&
						(temp=postFinder ? indexOf(seed,elem) : preMap[i])>-1 ){
						// seed比對的元素記為否值,results不比對的元素記為否值
						seed[temp]=!(results[temp]=elem);
					}
				}
			}
		}else{
			// matchOut與results相同,傳回空數組,否則傳回matchOut
			matcherOut=condense(
				matcherOut===results ?
					matcherOut.splice(preexisting,matcherOut.length) : matcherOut
			);
			if( postFinder ){
				// setMatcher(postFinder,postSelector)查詢temp下所有元素節點并過濾,與results合并
				postFinder(null,results,matcherOut,xml);
			}else{
				push.apply(results,matcherOut);
			}
		}
	});
}

// 擷取校驗函數
// 擷取校驗函數,matcher[expando]為真時通過setMatcher擷取特殊的校驗函數,單函數形式
// 普通的校驗函數為數組形式
// 逗号選擇器分割生成多個groups、單個groups有多個tokens
// 也即單個groups隻可能傳回數組形式的普通校驗函數或單函數形式的特殊校驗函數
function matcherFromTokens(tokens){
	var checkContext, matcher, j,
		len=tokens.length,
		leadingRelative=Expr.relative[tokens[0].type],
		implicitRelative=leadingRelative || Expr.relative[" "],
		i=leadingRelative ? 1 : 0,// 起始無"+|~| |>",從第二個項開始查找

		// 選擇器以">"起始等情況,判斷addCombinator層級關系校驗器修改後elem與context是否相符
		matchContext=addCombinator(function(elem){
			return elem===checkContext;
		},implicitRelative,true),
		matchAnyContext=addCombinator(function(elem){
			return indexOf(checkContext,elem)>-1;
		},implicitRelative,true),
		matchers=[function(elem,context,xml){
			var ret=( !leadingRelative && (xml || context!==outermostContext) ) || (
				(checkContext=context).nodeType ?
					matchContext(elem,context,xml) :
					matchAnyContext(elem,context,xml) );
			checkContext=null;
			return ret;
		}];

	// form#form .input選擇器,else語句分支添加form、#form兩個校驗函數
	// 空格比對Expr.relative[tokens[i].type],進入if語句,addCombinator将form、#form兩個校驗函數合并為一
	// 			addCombinator函數由傳參elem(seed或context下查找所有節點)擷取待校驗節點
	// 			生成新的校驗函數并傳回;elem為引用對象的形式,校驗過程中被改變(用于傳入嵌套的校驗函數.panel form#form .input)
	// .input生成另一校驗函數,同addCombinator建構的校驗函數平級
	// return傳回值再用elementMatcher進行包裝,先執行.input校驗函數,再執行addCombinator建構的校驗函數
	for ( ; i<len; i++ ){
		if ( (matcher=Expr.relative[tokens[i].type]) ){
			matchers=[addCombinator(elementMatcher(matchers),matcher)];
		}else{
			// Expr.filter[tokens[i].type]傳參為待比對的選擇器參數
			// 通過Expr.filter[tokens[i].type]傳回校驗函數
			// 如.className選擇器,matcher為Expr.filter["ClASS"]("className")
			// gt(1)選擇器,matcher為Expr.pesudos["gt"](0)
			matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);

			// matcher[expando]為真時,特殊的過濾方法,通過傳遞引用對象的形式改寫後擷取結果
			// 普通過濾通過傳回值得到結果
			// :not、:first等僞類可能是matcher[expando]真值情況,傳回過濾函數
			if ( matcher[expando] ){
				j=++i;
				for ( ; j<len; j++ ){
					if ( Expr.relative[tokens[j].type] ){
						break;
					}
				}
				return setMatcher(
					i>1 && elementMatcher(matchers),// :not之前選擇器的校驗函數
					i>1 && toSelector(
						tokens.slice(0,i-1).concat({value:tokens[i-2].type===" " ? "*" : "" })
					).replace(rtrim,"$1"),// :not之前選擇器完全值,後加"*"或""
					matcher,// :not選擇器的校驗函數
					i<j && matcherFromTokens(tokens.slice(i,j)),// :not之後的校驗函數,"+"等操作符前
					j<len && matcherFromTokens((tokens=tokens.slice(j))),// :not之後的校驗函數,"+"等操作符後
					j<len && toSelector(tokens)// 選擇器完全值
				);
			}
			matchers.push(matcher);
		}
	}

	return elementMatcher(matchers);
}

// 由校驗函數集elementMatchers、setMatchers建構superMatch超級比對函數并傳回
function matcherFromGroupMatchers(elementMatchers,setMatchers){
	var bySet=setMatchers.length>0,
		byElement=elementMatchers.length>0,
		superMatcher=function(seed,context,xml,results,outermost){
			var elem, j, matcher,
				matchedCount=0,
				i="0",
				unmatched=seed && [],
				setMatched=[],
				contextBackup=outermostContext,
				// 無待比對元素seed,outermost上下文中擷取所有元素節點
				elems=seed || byElement && Expr.find["TAG"]("*",outermost),
				// Use integer dirruns iff this is the outermost matcher
				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
				len=elems.length;

			if ( outermost ){
				outermostContext=context===document || context || outermost;
			}

			for ( ; i!==len && (elem=elems[i])!=null; i++ ){
				// 在outermost中找出所有tag節點,調用elementMatchers中比對函數校驗其是否滿足條件
				// 逗号分割的選擇器前後無:first等需要特殊校驗的選擇器,results直接推入比對的元素
				if ( byElement && elem ){
					j=0;
					if ( !context && elem.ownerDocument!==document ){
						setDocument(elem);
						xml=!documentIsHTML;
					}
					// 怎樣處理addCombinator層級校驗函數中elem被改變的事實???
					while ( (matcher=elementMatchers[j++]) ){
						if ( matcher(elem,context || document,xml) ){
							results.push(elem);
							break;
						}
					}
					if ( outermost ){
						dirruns=dirrunsUnique;
					}
				}

				if ( bySet ){
					// matchedCount标記elem元素不比對elementMatchers普通校驗,需要用setMatchers校驗
					if ( (elem=!matcher && elem) ){
						matchedCount--;
					}

					// 無seed時,setMatchers将在context查找所有節點并尋找比對元素
					// 有seed,setMatchers将在context下查找unmatched内元素
					if ( seed ){
						unmatched.push(elem);
					}
				}
			}

			// 已比對elementMatchers的元素個數,其餘元素需要用setMatchers校驗
			matchedCount+=i;

			if ( bySet && i!==matchedCount ){
				j=0;
				while ( (matcher=setMatchers[j++]) ){
					// 包裝後的setMatchers獲得unmatched比對的為否值,setMatched隻包含比對的元素
					// 無seed時,unmatched為空數組,context查找所有節點并尋找比對元素
					// 有seed,context下查找unmatched内元素
					matcher(unmatched,setMatched,context,xml);
				}

				if ( seed ){
					// 有seed時,setMatchers過濾結果中setMatched未比對項記為否
					if ( matchedCount>0 ){
						while ( i-- ){
							if ( !(unmatched[i] || setMatched[i]) ){
								setMatched[i]=pop.call(results);
							}
						}
					}

					// 移除值為false的數組項,保留值為節點的數組項,即比對結果
					setMatched=condense(setMatched);
				}

				// select方法将直接獲得results結果集,無須傳回results
				push.apply(results,setMatched);

				if ( outermost && !seed && setMatched.length>0 &&
					( matchedCount+setMatchers.length )>1 ){

					Sizzle.uniqueSort(results);
				}
			}

			// Override manipulation of globals by nested matchers???
			if ( outermost ){
				dirruns=dirrunsUnique;
				outermostContext=contextBackup;
			}

			return unmatched;
		};

	return bySet ? markFunction(superMatcher) : superMatcher;
}

// 擷取超級比對函數
// 通過matcherFromTokens擷取校驗函數集elementMatchers、setMatchers
// 接着由matcherFromGroupMatchers函數建構superMatch函數并傳回
// 傳回值為函數,該函數的傳回值為superMatch超級查詢并校驗比對函數
compile=Sizzle.compile=function(selector,match/* Internal Use Only */){
	var i,
		setMatchers=[],
		elementMatchers=[],
		cached=compilerCache[selector+" "];

	if ( !cached ){
		if ( !match ){
			match=tokenize(selector);
		}
		i=match.length;// 逗号分隔的選擇器個數
		while ( i-- ){
			// 逗号分隔的選擇器通過matcherFromTokens擷取校驗函數
			// 隻可能是數組形式的普通檢驗函數,推送到elementMatchers中
			// 或者函數形式的特殊校驗函數,推送到setMatchers中
			// 是以setMatchers、elementMatchers各自擷取到的結果是逗号分割選擇器的各自結果,不需要再過濾
			cached=matcherFromTokens(match[i]);
			if ( cached[expando] ){
				// 特殊校驗 如:not、:first等,以待校驗元素、結果集作為參數傳入過濾
				// 引用對象形式過濾待校驗元素及結果集
				setMatchers.push(cached);
			}else{
				// 單元素校驗 如tag、id等,以校驗元素作為參數傳入,傳回值為布爾類型
				elementMatchers.push(cached);
			}
		}

		// 傳回值,向superMatch函數傳入校驗函數集elementMatchers、setMatchers
		// cached存儲校驗函數
		cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers));
		cached.selector=selector;
	}
	return cached;
};

// 在不能使用qsa或相容性問題,或選擇器語句複雜的情況下,使用select函數進行查詢
// 單一選擇器無逗号分割時,調用getElementById或Expr.find[type]進行查找
// 有逗号分割,調用select方法周遊dom樹,Expr.filter方法過濾,擷取結果集
select=Sizzle.select=function(selector,context,results,seed){
	var i, tokens, token, type, find,
		compiled=typeof selector==="function" && selector,// 選擇器為超級比對函數
		match=!seed && tokenize( (selector=compiled.selector || selector) );

	results=results || [];

	// 逗号分隔的選擇器隻有一個,且不存在seed
	if ( match.length===1 ){

		// id選擇器快速查找," #id + :lt(3) > .tag"快速找到#id,并且更新context
		tokens=match[0]=match[0].slice(0);
		if ( tokens.length>2 && (token=tokens[0]).type==="ID" &&
				support.getById && context.nodeType===9 && documentIsHTML &&
				Expr.relative[tokens[1].type] ){

			context=(Expr.find["ID"](token.matches[0].replace(runescape,funescape),context) || [])[0];
			if ( !context ){
				return results;
			}else if( compiled ){// selector為函數
				context=context.parentNode;
			}

			selector=selector.slice(tokens.shift().value.length);// 移除已經找到的id節點
		}

		i=matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
		// 其他選擇器或以"+|~| |>"的選擇器通過Expr.find[type]查找
		while ( i-- ){// 選擇器自右向左查找
			token=tokens[i];

			// "+","~",">"," "執行跳出循環
			if ( Expr.relative[(type=token.type)] ){
				break;
			}

			// "+ :lt(3) > .tag"情形找到.tag,其餘通過超級比對函數superMatch查找
			if ( (find=Expr.find[type]) ){
				// 選擇器以">"、" "起始context中查詢,選擇器以"+"、"~"起始context父節點中查詢
				if ( (seed=find(
					token.matches[0].replace(runescape,funescape),
					rsibling.test(tokens[0].type) && testContext(context.parentNode) || context
				)) ){
					tokens.splice(i,1);
					selector=seed.length && toSelector(tokens);
					if ( !selector ){// seed存儲已找到的元素,選擇器查詢完畢時,填入results中
						push.apply(results,seed);
						return results;
					}

					break;
				}
			}
		}
	}

	// 傳參有seed,或Expr.find無法找到的内容,調用超級比對函數superMatch查詢文檔樹,并獲得結果集
	( compiled || compile(selector,match) )(
		seed,// 待比對元素
		context,// 上下文
		!documentIsHTML,
		results,// 查詢結果集
		// superMatch函數查找所有tag節點的上下文
		!context || rsibling.test(selector) && testContext(context.parentNode) || context
	);
	return results;
};

// 將hasDuplicate指派為true,support.sortStable為真
support.sortStable=expando.split("").sort(sortOrder).join("")===expando;

// Support: Chrome 14-35+ support.detectDuplicates設定為真值,允許重複項
support.detectDuplicates=!!hasDuplicate;

// 初始化設定document,相容性情況support擷取,根據相容性設定部分特殊的find、filter方法
setDocument();

// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// 兩個未插入文檔的元素調用compareDocumentPosition方法理應傳回1,不相容時傳回4
// support.sortDetached為否
support.sortDetached=assert(function(el){
	return el.compareDocumentPosition(document.createElement("fieldset")) & 1;
});

// 針對相容性問題添加特殊的屬性擷取方法

// Support: IE<8
if ( !assert(function(el){
	el.innerHTML="<a href='#'></a>";
	return el.firstChild.getAttribute("href")==="#";
}) ){// 沒報錯向Expr.attrHandle添加方法
	addHandle("type|href|height|width",function(elem,name,isXML){
		if ( !isXML ){
			// 次參為2時,屬性值以字元串形式傳回;為1時,嚴格區分大小寫
			// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
			return elem.getAttribute(name,name.toLowerCase()==="type" ? 1 : 2 );
		}
	});
}

// Support: IE<9 使用elem.defaultValue替代getAttribute("value")
if ( !support.attributes || !assert(function(el){
	el.innerHTML="<input/>";
	el.firstChild.setAttribute("value","");
	return el.firstChild.getAttribute("value")==="";
}) ){
	addHandle("value",function(elem,name,isXM ){
		if ( !isXML && elem.nodeName.toLowerCase()==="input" ){
			return elem.defaultValue;
		}
	});
}

// Support: IE<9 使用getAttributeNode方法擷取布爾值,替代取值有問題的getAttribute
if ( !assert(function(el){
	return el.getAttribute("disabled")==null;
}) ){
	addHandle(booleans,function(elem,name,isXML){
		var val;
		if ( !isXML ){
			return elem[name]===true ? name.toLowerCase() :
					(val=elem.getAttributeNode(name)) && val.specified ?
					val.value : null;
		}
	});
}

var _sizzle=window.Sizzle;

// window.Sizzle被占用的情況下,使用完畢執行noConflict,window.Sizzle還原為初始值

Sizzle.noConflict=function() {
	if ( window.Sizzle===Sizzle ) {
		window.Sizzle=_sizzle;
	}

	return Sizzle;
};

// AMD/CMD子產品化加載

if ( typeof define==="function" && define.amd ){
	define(function(){ return Sizzle; });
}else if( typeof module!=="undefined" && module.exports ){
	module.exports=Sizzle;
}else{
	window.Sizzle=Sizzle;
}

})( window );

      

selector-sizzle.js

define([
	"./core",
	"../external/sizzle/dist/sizzle"
],function(jQuery,Sizzle){

jQuery.find=Sizzle;// 查找,第四參數為期望比對項,若有,從期望比對項中查找結果
jQuery.expr=Sizzle.selectors;// 開發者擴充sizzle

jQuery.expr[":"]=jQuery.expr.pseudos;// 添加僞類選擇器
jQuery.uniqueSort=jQuery.unique=Sizzle.uniqueSort;// 去重并排序
jQuery.text=Sizzle.getText;// 拼接文本
jQuery.isXMLDoc=Sizzle.isXML;// 是否xml
jQuery.contains=Sizzle.contains;// 包含
jQuery.escapeSelector=Sizzle.escape;// 轉義

});
      

selector-native.js(不使用sizzle,而用qsa原生語句)

define([
	"./core",
	"./var/document",
	"./var/documentElement",
	"./var/hasOwn",
	"./var/indexOf"
],function(jQuery,document,documentElement,hasOwn,indexOf){

// 不使用sizzle,使用qsa查詢

var hasDuplicate, sortInput,
	sortStable=jQuery.expando.split("").sort(sortOrder).join("")===jQuery.expando,
	matches=documentElement.matches ||
		documentElement.webkitMatchesSelector ||
		documentElement.mozMatchesSelector ||
		documentElement.oMatchesSelector ||
		documentElement.msMatchesSelector,

	rcssescape=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,
	fcssescape=function(ch,asCodePoint){
		if ( asCodePoint ){
			if ( ch==="\0" ){
				return "\uFFFD";
			}

			return ch.slice(0,-1)+"\\"+ch.charCodeAt(ch.length-1).toString(16)+" ";
		}

		return "\\"+ch;
	};

function sortOrder(a,b){

	if ( a===b ) {
		hasDuplicate=true;
		return 0;
	}

	var compare=!a.compareDocumentPosition-!b.compareDocumentPosition;
	if ( compare ){
		return compare;
	}

	compare=( a.ownerDocument || a )===( b.ownerDocument || b ) ?
		a.compareDocumentPosition(b) : 1;

	if ( compare & 1 ){

		if ( a===document || a.ownerDocument===document && jQuery.contains(document,a) ){
			return -1;
		}
		if ( b===document || b.ownerDocument===document && jQuery.contains(document,b) ){
			return 1;
		}

		return sortInput ?
			( indexOf.call(sortInput,a)-indexOf.call(sortInput,b) ) : 0;
	}

	return compare & 4 ? -1 : 1;
}

// 調用sortOrder先排序,再去重
function uniqueSort(results){
	var elem,
		duplicates=[],
		j=0,
		i=0;

	hasDuplicate=false;// 有無重複項
	sortInput=!sortStable && results.slice(0);
	results.sort(sortOrder);

	if ( hasDuplicate ){
		while ( ( elem=results[i++ ]) ){
			if ( elem===results[i] ){
				j=duplicates.push(i);
			}
		}
		while ( j-- ){
			results.splice(duplicates[j],1);
		}
	}

	sortInput=null;

	return results;
}

function escape(sel){
	return (sel+"").replace(rcssescape,fcssescape);
}

jQuery.extend( {
	uniqueSort:uniqueSort,// 去重并排序
	unique:uniqueSort,
	escapeSelector:escape,// 轉義
	// 有seed,h5語句過濾查詢,無seed,qsa語句查詢
	find: function(selector,context,results,seed){
		var elem, nodeType,
			i = 0;

		results=results || [];
		context=context || document;

		if ( !selector || typeof selector!=="string" ){
			return results;
		}

		if ( ( nodeType=context.nodeType )!==1 && nodeType!==9 ){
			return [];
		}

		if ( seed ){
			while ( ( elem=seed[i++] ) ) {
				if ( jQuery.find.matchesSelector(elem,selector) ){
					results.push(elem);
				}
			}
		} else {
			jQuery.merge(results,context.querySelectorAll(selector));
		}

		return results;
	},
	// 以textContent或nodeValue屬性擷取單元素或多元素的文本内容
	text:function(elem){
		var node,
			ret="",
			i=0,
			nodeType=elem.nodeType;

		if ( !nodeType ){
			while ( ( node=elem[i++] ) ){
				ret += jQuery.text(node);
			}
		}else if( nodeType===1 || nodeType===9 || nodeType===11 ){
			return elem.textContent;
		}else if( nodeType===3 || nodeType===4 ){
			return elem.nodeValue;
		}

		return ret;
	},
	// 原生語句判斷是否包含,a、b為dom對象的形式
	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(bup) );
	},
	// 判斷是否xml
	isXMLDoc:function(elem){
		var documentElement=elem && (elem.ownerDocument || elem).documentElement;
		return documentElement ? documentElement.nodeName!=="HTML" : false;
	},
	expr:{
		attrHandle:{},// 由開發者添加擷取屬性的方法
		match: {
			bool:new RegExp( "^(?:checked|selected|async|autofocus|autoplay|controls|defer" +
				"|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$", "i" ),
			needsContext: /^[\x20\t\r\n\f]*[>+~]/
		}
	}
} );

jQuery.extend(jQuery.find,{
	// elements濾除不比對expr的元素
	matches:function(expr,elements){
		return jQuery.find(expr,null,null,elements);
	},
	// 使用原生語句判斷元素是否比對選擇器
	matchesSelector:function(elem,expr){
		return matches.call(elem,expr);
	},
	// 自定義jQuery.expr擷取屬性,差別對待xml的考慮,否則使用elem.getAttribute方法
	attr:function(elem,name){
		var fn=jQuery.expr.attrHandle[name.toLowerCase()],

			value=fn && hasOwn.call( jQuery.expr.attrHandle,name.toLowerCase() ) ?
				fn(elem,name,jQuery.isXMLDoc(elem)) :
				undefined;
		return value!==undefined ? value : elem.getAttribute(name);
	}
});

});
      

繼續閱讀