jquery 源码分析六 - Sizzle

以下吐槽:

   最近一直在面试啊找工作啊,然后学校里又有一堆事情,结果看代码的时间变少了。憋了好几天终于感觉可以写一篇文章了,早上就爬起来赶紧写下来,怕又忘了。吐槽下:小本科找工作真的好难。。。。

正文开始:

首先是Sizzle里面的一些基础方法,也可是说是用的比较多的东西。因为Sizzle一开始就定义了许许多多的变量,所以这边先讲一些这次会用到的变量(比较简单的。。)

 1     expando = "sizzle" + -(new Date()),
 2     //给每个Sizzle生成一个特征码,区别每个sizzle
 3     preferredDoc = window.document,
 4     //指向document
 5     dirruns = 0,
 6     done = 0,
 7     classCache = createCache(),
 8     tokenCache = createCache(),
 9     compilerCache = createCache(),
10     //这个制造了一个存储的空间,具体的createCache函数会在下面讲
11     sortOrder = function( a, b ) {
12         if ( a === b ) {
13             hasDuplicate = true;
14         }
15         return 0;
16     },
17 
18     // 未定义
19     strundefined = typeof undefined,
20     MAX_NEGATIVE = 1 << 31,
21 
22     // 定义原生的方法,方便后面快速使用
23     hasOwn = ({}).hasOwnProperty,
24     arr = [],
25     pop = arr.pop,
26     push_native = arr.push,
27     push = arr.push,
28     slice = arr.slice,
29     // 如果原生的indexOf没有的话,就用自己写得函数
30     indexOf = arr.indexOf || function( elem ) {
31         var i = 0,
32             len = this.length;
33         for ( ; i < len; i++ ) {
34             if ( this[i] === elem ) {
35                 return i;
36             }
37         }
38         return -1;
39     },

注意:这里的代码都是在开头var里面截取出来的,所以后面都是逗号。。。

下面是关于createCache(),createCache返回的是一个function,这个函数接受两个参数,分别是key,value。key值会存入keys 数组中,然后value会放到这个函数作为object形式的相应key值下,具体代码如下:

 1 function createCache() {
 2     var keys = [];
 3 
 4     function cache( key, value ) {
 5         // 用key+ " "来防止覆盖原生的一些方法
 6         if ( keys.push( key + " " ) > Expr.cacheLength ) {
 7             //若超过数量限制,就把最前面的一些数弹出
 8             delete cache[ keys.shift() ];
 9         }
10         return (cache[ key + " " ] = value);
11     }
12     return cache;
13 }

 接下来是一些正则表达式,备份正则表达式还没理解,所以有注释的只是其中部分:

 1     //用于检测空格符,包括回车之类的
 2     whitespace = "[\\x20\\t\\r\\n\\f]",
 3     // 检测由\\.或字符-或非ASCII从00到a0的值
 4     characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
 5 
 6     // 这个还没理解,英文翻译了也没看懂。。但是应该是用来匹配css的
 7     // 一个未被应用的值应该是css标识符http://www.w3.org/TR/css3-selectors/#attribute-selectors
 8     // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
 9     identifier = characterEncoding.replace( "w", "w#" ),
10 
11     // 用来匹配attribute的,有点长。。。
12     attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
13         "*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
14 
15     // Prefer arguments quoted,
16     //   then not containing pseudos/brackets,
17     //   then attribute selectors/non-parenthetical expressions,
18     //   then anything else
19     // These preferences are here to reduce the number of selectors
20     //   needing tokenize in the PSEUDO preFilter
21     pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
22 
23     // 检测字符串首尾空白符用的
24     rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
25         //用来检测逗号前后的空白的
26     rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
27     rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
28 
29     rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
30 
31     rpseudo = new RegExp( pseudos ),
32     ridentifier = new RegExp( "^" + identifier + "$" ),
33         //根据不同的属性建立不同的正则,后面可以分离检测不同的css selector部分
34     matchExpr = {
35         "ID": new RegExp( "^#(" + characterEncoding + ")" ),
36         "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
37         "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
38         "ATTR": new RegExp( "^" + attributes ),
39         "PSEUDO": new RegExp( "^" + pseudos ),
40         "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
41             "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
42             "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
43         "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
44         // 用于 .is()
45         "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
46             whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
47     },
48         //input类型检测
49     rinputs = /^(?:input|select|textarea|button)$/i,
50     rheader = /^h\d$/i,
51         //是否有原生代码
52     rnative = /^[^{]+\{\s*\[native \w/,
53 
54     // 快速简单的检测ID TAG CLASS
55     rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
56 
57     rsibling = /[+~]/,
58     rescape = /'|\\/g,
59 
60     // 没搞懂。。。CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
61     runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
62     funescape = function( _, escaped, escapedWhitespace ) {
63         var high = "0x" + escaped - 0x10000;
64         // NaN means non-codepoint
65         // Support: Firefox
66         // Workaround erroneous numeric interpretation of +"0x"
67         return high !== high || escapedWhitespace ?
68             escaped :
69             high < 0 ?
70                 // BMP codepoint
71                 String.fromCharCode( high + 0x10000 ) :
72                 // Supplemental Plane codepoint (surrogate pair)
73                 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
74     };

还有一段关于push那些NodeList的bug修复,在Android小于4.0的浏览器中,push会静默的失败,所以为了兼容这个,就需要写一个自己的push方法,jquery代码如下:

try {
    push.apply(
        (arr = slice.call( preferredDoc.childNodes )),
        preferredDoc.childNodes
    );
    // 检测Android<4.0
    // push静默的失败,下面这句会抛出错误
    arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
    push = { apply: arr.length ?

        // 尽量使用原生的push
        function( target, els ) {
            push_native.apply( target, slice.call(els) );
        } :

        // 对于IE9
        // 用自己的方法,直接添加到后面
        function( target, els ) {
            var j = target.length,
                i = 0;
            // 需要自己设置length,length不可靠
            while ( (target[j++] = els[i++]) ) {}
            target.length = j - 1;
        }
    };
}

下一篇会分析的是Sizzle比较核心的代码,已经看了一大部分了,会尽快发上来,不会拖延很长时间的(谁来拯救我的拖延症。。)

posted @ 2014-03-13 10:18  胖蝎子  阅读(282)  评论(0编辑  收藏  举报