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 lang="en"/>或<div lang="en-us"/>
		"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 elemLang===lang || 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);
	}
});

});

 

猜你喜欢

转载自schifred.iteye.com/blog/2334495
今日推荐