jquery 源码分析九 - Sizzle
最近一直在搞毕设,实在是没时间写博客了,零碎的时间看代码进度也不快,所以写博客一拖再拖了,今天先补一篇上来。。。
在上次写得setDocument以后,紧接着的是一些零碎的功能函数
1 Sizzle.matches = function( expr, elements ) { 2 return Sizzle( expr, null, null, elements ); 3 }; 4 5 Sizzle.matchesSelector = function( elem, expr ) { 6 // 设置document以防万一 7 if ( ( elem.ownerDocument || elem ) !== document ) { 8 setDocument( elem ); 9 } 10 11 // 确保属性值被引号包裹 12 expr = expr.replace( rattributeQuotes, "='$1']" ); 13 14 if ( support.matchesSelector && documentIsHTML && 15 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && 16 ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { 17 18 try { 19 var ret = matches.call( elem, expr ); 20 21 // 在IE9下matchesSelector会返回false(在IE10+情况下,开发者模式调到IE9,8是正常的,IETester下返回false) 22 if ( ret || support.disconnectedMatch || 23 // 同样的,在IE9下,这种无关节点被认为是在文档片段中 24 elem.document && elem.document.nodeType !== 11 ) { 25 return ret; 26 } 27 } catch(e) {} 28 } 29 30 return Sizzle( expr, document, null, [elem] ).length > 0; 31 }; 32 33 Sizzle.contains = function( context, elem ) { 34 // 设置document 35 if ( ( context.ownerDocument || context ) !== document ) { 36 setDocument( context ); 37 } 38 return contains( context, elem ); 39 }; 40 41 Sizzle.attr = function( elem, name ) { 42 // 设置document 43 if ( ( elem.ownerDocument || elem ) !== document ) { 44 setDocument( elem ); 45 } 46 47 var fn = Expr.attrHandle[ name.toLowerCase() ], 48 // 防止取到Object.prototype里的属性 (jQuery #13807) 49 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? 50 fn( elem, name, !documentIsHTML ) : 51 undefined; 52 53 return val !== undefined ? 54 val : 55 support.attributes || !documentIsHTML ? 56 elem.getAttribute( name ) : 57 (val = elem.getAttributeNode(name)) && val.specified ? 58 val.value : 59 null; 60 }; 61 62 Sizzle.error = function( msg ) { 63 throw new Error( "Syntax error, unrecognized expression: " + msg ); 64 };
在这边,Sizzle.matches和Sizzle.matchesSelector在最后都是以return Sizzle( expr, null, null, elements )形式返回的,由于在Sizzle中,在第四项有值时,就会跳过一个大的if语句块
if ( documentIsHTML && !seed ) { }
然后会直接跳到最后执行select函数
return select( selector.replace( rtrim, "$1" ), context, results, seed );
对于select函数,先放一下。。。等看到的时候再分析。。。
接下来的是一个主要剔除重复+排序的函数,源码如下:
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 ) { while ( (elem = results[i++]) ) { if ( elem === results[ i ] ) { j = duplicates.push( i ); } } while ( j-- ) { results.splice( duplicates[ j ], 1 ); } } // See https://github.com/jquery/sizzle/pull/225 sortInput = null; return results; };
在这里一开始先默认确实有重复项,然后在result.sort的时候,用sortOrder来排序,这个函数在setDocument中定义了,其中有一段就是设置hasDuplicate的:
if ( a === b ) { hasDuplicate = true; }
注:hasDuplicate在Sizzle闭包作用域中属于全局变量。
然后是一个拿元素内文本内容的函数,主要调用了textContent,源码如下:
1 getText = Sizzle.getText = function( elem ) { 2 var node, 3 ret = "", 4 i = 0, 5 nodeType = elem.nodeType; 6 7 if ( !nodeType ) { 8 // 如果没有nodeType,那么就认为是一个普通数组 9 while ( (node = elem[i++]) ) { 10 ret += getText( node ); 11 } 12 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { 13 // 对于元素用textContent 14 // innerText 已被移除 15 if ( typeof elem.textContent === "string" ) { 16 return elem.textContent; 17 } else { 18 // 对子节点遍历 19 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { 20 ret += getText( elem ); 21 } 22 } 23 } else if ( nodeType === 3 || nodeType === 4 ) { 24 return elem.nodeValue; 25 } 26 // 排除注释节点 27 28 return ret; 29 };
它用了一个递归调用的方法,防止注释等节点的混入。
在后面就是一个
1 Expr = Sizzle.selectors = { 2 // ..... 3 }
这里放了许多关于筛选元素的函数,暂时先跳过了。下一篇的话从后面的tokenize开始讲。明后天估计还是要去实验室搬砖,争取在零碎时间多看看源码,早点把下一篇发上来。。。
这篇好像有点短了。。。