天天看點

jQuery技術内幕:深入解析jQuery架構設計與實作原理. 3.9 Sizzle.selectors

<b>3.9 sizzle.selectors</b>

對象sizzle.selectors包含了sizzle在查找和過濾過程中用到的正則、查找函數、過濾函數,其中包含的屬性見圖3-1,源碼結構見代碼清單3-1。

3.9.1 sizzle.selectors.order

表達式類型數組sizzle.selectors.order中定義了查找單個塊表達式時的查找順序,依次是id、class、name、tag。其中,class需要浏覽器支援方法getelementsbyclass

name()。查找順序綜合考慮了浏覽器是否支援、查找結果集的大小、查找效率、使用頻率等因素。

相關代碼如下所示:

4221 var expr =

sizzle.selectors = {

4222    

order: [ "id", "name", "tag" ],

4749 };

5139 (function(){

5140    

var div = document.createelement("div");

5141

5142    

div.innerhtml = "&lt;div class='test e'&gt;&lt;/div&gt;&lt;div

class='test'&gt;&lt;/div&gt;";

5143

5144    

// opera can't find a second classname (in 9.6)

5145    

// also, make sure that getelementsbyclassname actually exists

5146    

if ( !div.getelementsbyclassname ||

div.getelementsbyclassname("e").length === 0 ) {

5147        

return;

5148    

}

5149

5150    

// safari caches class attributes, doesn't catch changes (in 3.2)

5151    

div.lastchild.classname = "e";

5152

5153    

if ( div.getelementsbyclassname("e").length === 1 ) {

5154        

5155    

5156    

5157    

expr.order.splice(1, 0, "class");

5158    

expr.find.class = function( match, context, isxml ) {

5159        

if ( typeof context.getelementsbyclassname !== "undefined"

&amp;&amp; !isxml ) {

5160             return

context.getelementsbyclassname(match[1]);

5161        

5162  

  };

5163

5164    

// release memory in ie

5165    

div = null;

5166 })();

第5140~5155行:測試目前浏覽器是否正确支援方法getelementsbyclassname()。測試思路是先構造一段dom結構,然後調用方法getelementsbyclassname(),檢查是否傳回期望數量的元素。如果不支援或不能正确支援,則不做任何事情。

第5157~5162行:如果目前浏覽器支援方法getelementsbyclassname(),則:

向sizzle.selectors.order中插入"class",由["id", "name", "tag"]變為["id",

"class", "name", "tag"],插入位置在"id"之後、"name"之前。

向sizzle.selectors.find中插入"class"對應的查找函數。

3.9.2 sizzle.selectors.match/leftmatch

對象sizzle.selectors.match/leftmatch中存放了表達式類型和正則的映射,正則用于确定塊表達式的類型,并解析其中的參數。

4221 var expr = sizzle.selectors = {

4224    

match: {

4225        

id: /#((?:[\w\u00c0-\uffff\-]|\\.)+)/,

4226        

class: /\.((?:[\w\u00c0-\uffff\-]|\\.)+)/,

4227        

name: /\[name=['"]*((?:[\w\u00c0-\uffff\-]|\\.)+)['"]*\]/,

4228        

attr:

/\[\s*((?:[\w\u00c0-\uffff\-]|\\.)+)\s*(?:(\s?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uffff\-]|\\.)*)|)|)\s*\]/,

4229        

tag: /^((?:[\w\u00c0-\uffff\*\-]|\\.)+)/,

4230        

child: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|

(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,

4231        

pos: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,

4232        

pseudo: /:((?:[\w\u00c0-\uffff\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]

*)+)\2\))?/

4233    

},

4749 };

4751 var origpos = expr.match.pos,

4752    

fescape = function(all, num){

4753        

return "\\" + (num - 0 + 1);

4754    

};

4755

4756 for ( var type in expr.match ) {

4757  

  expr.match[ type ] = new regexp(

expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );

4758    

expr.leftmatch[ type ] = new regexp( /(^(?:.|\r|\n)*?)/.source +

expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );

4759 }

第4224~4233行:定義一組正則,稍後會逐個分析和測試。

第4756~4759行:為對象sizzle.sectors.match中的正則增加一段字尾正則/(?![^\[]*\])(?![^\()*\])/,然後再加上一段字首正則/(^(?:.|\r|\n)*?)/,來構造對象sizzle.sectors.leftmatch中的同名正則。因為增加的字首正則中包含了一個分組,是以原正則中的分組編号需要加1後移。

1.?字尾正則/(?![^\[]*\])(?![^\()*\])/

字尾正則/(?![^\[]*\])(?![^\()*\])/要求接下來的字元不能含有"]"、")",用于確定選擇器表達式的文法正确,以及確定正确比對嵌套選擇器表達式。

例如,執行$("input[name=foo\\.baz]]")時會抛出文法異常,因為選擇器表達式"input

[name=foo\\.baz]]"的末尾多了一個"]",對象sizzle.selectors.match/leftmatch中沒有正則可以比對其中的"[name=foo\\.baz]]";如果沒有字尾正則,則sizzle.selectors.match/leftmatch.name會比對"[name=foo\\.baz]]",并執行查找,而不會抛出文法異常。

又如,執行$("input[name=foo.baz]")時會抛出文法異常,因為選擇器表達式"input

[name=foo.baz]"沒有轉義點号,對象sizzle.selectors.match/leftmatch中沒有正則可以比對其中的"[name=foo.baz]";如果沒有字尾正則,則對象sizzle.selectors.match/leftmatch.class會比對"input[name=foo.baz]"中的".baz",并執行查找,然後用"input[name=foo

]"過濾查找結果,而不會抛出文法異常。

再如,執行$("input:not(.foo)")時,會先查找比對"input"的元素集合,然後從中過濾不比對".foo"的元素集合;如果沒有字尾正則,則會變為先查找比對".foo"的元素集合,然後從中過濾比對"input:not()"的元素集合。

讀者可以将第4757行代碼注釋掉,然後測試和驗證上述例子。

2.?字首正則/(^(?:.|\r|\n)*?)/

字首正則/(^(?:.|\r|\n)*?)/用于捕獲比對正則的表達式之前的字元,主要是捕獲轉義反斜杠,以支援将特殊字元作為普通字元使用。

例如,".test\\#id",在用正則sizzle.selectors.match.id比對時會發現"#"之前是轉義反斜杠"\\",這時将認為該表達式的類型不是id;如果沒有字首正則,則會先查找比對"#id"的元素集合,然後從中過濾出比對".test\\"的元素集合。

接下來分析和測試對象sizzle.selectors.match中id、class、name、attr、tag、child、pos、pseudo對應的正則。測試用例參考自sizzle的測試用例https://github.com/jquery/sizzle/blob/1.7.1/test/unit/selector.js。

3.?id

正則sizzle.selector.match.id用于比對簡單表達式"#id",并解析"#"之後的字元串,其中含有1個分組:id。解析圖見圖3-7,測試用例見表3-3。

圖3-7 正則sizzle.selectors.match.id

表3-3 正則 sizzle.selectors.match.id

序  号         測 試 用 例  運作結果

1       id.exec("#id") ["#id", "id"]

2       id.exec("#firstp#simon1")       ["#firstp", "firstp"]

3       id.exec("#台北ta?ibe?i")       ["#台北ta?ibe?i",

"台北ta?ibe?i"]

4       id.exec("#foo\\:bar")      ["#foo\\:bar",

"foo\\:bar"]

5       id.exec("#test\\.foo\\[5\\]bar")      ["#test\\.foo\\[5\\]bar",

"test\\.foo\\[5\\]bar"]

4.?class

正則 sizzle.selector.match.class 用于比對簡單表達式".class",并解析"."之後的字元串,其中含有1個分組:類樣式。解析圖見圖3-8,測試用例見表3-4。

圖3-8 正則sizzle.selectors.match.class

表3-4  正則

sizzle.selectors.match.class

序  号         測 試 用 例  運

行 結 果

1       class.exec(".blog")         [".blog", "blog"]

2       class.exec(".blog.link")  [".blog", "blog"]

3       class.exec(".台北ta?ibe?i") [".台北ta?ibe?i",

4       class.exec(".foo\\:bar")          [".foo\\:bar",

5       class.exec(".test\\.foo\\[5\\]bar")         [".test\\.foo\\[5\\]bar",

5.?name

正則sizzle.selector.match.name用于比對屬性表達式"[ name

= "value" ]",并解析屬性name的值,其中含有1個分組:屬性name的值。解析圖見圖3-9,測試用例見表3-5。

圖3-9 正則sizzle.selectors.match.name

表3-5 正則 sizzle.selectors.match.name

1       name.exec("input[name=action]")         ["[name=action]", "action"]

2       name.exec("input[name='action']")       ["[name='action']",

"action"]

3       name.exec("input[name=\"action\"]")  ["[name="action"]",

4       name.exec("input[name=\"types[]\"]")          null

6.?attr

正則sizzle.selector.match.attr用于比對屬性表達式"[attribute

= "value"]",并解析屬性名和屬性值,其中含有5個分組:屬性名、等号部分、引号、屬性值、無引号時的屬性值。解析圖見圖3-10,測試用例見表3-6。

7.tag

正則sizzle.selector.match.tag用于比對簡單表達式"tag",并解析标簽名,其中含有1個分組:标簽名。解析圖見圖3-11,測試用例見表3-7。

8.?child

正則sizzle.selector.match.child用于比對子元素僞類表達式:nth-child(index/even/odd/equation)、:first-child、:last-child、:only-child,并解析子元素僞類和僞類參數,其中含有2個分組:子元素僞類、僞類參數。解析圖見圖3-12,測試用例見表3-8。

9.?pos

正則sizzle.selector.match.pos用于比對位置僞類表達式":eq(index)"、":gt(index)"、":lt(index)"、":first"、":last"、":odd"、":even",并解析位置僞類和僞類參數,其中含有2個分組:位置僞類、僞類參數。解析圖見圖3-13,測試用例見表3-9。

10.?pseudo

正則 sizzle.selector.match.pseudo 用于比對僞類表達式,請解析

":" 之後的僞類和僞類參數,其中含有 3 個分組:僞類、引号、僞類參數。解析圖見圖3-14,測試用例見表3-10。

表3-6 正則sizzle.selectors.match.attr

序号         測 試 用 例  運

1       attr.exec("a[title]")        ["[title]", "title",

undefined, undefined, undefined, undefined]

2       attr.exec("a[title=]")     ["[title=]", "title",

"=", undefined, undefined, ""]

3       attr.exec("a[rel='bookmark']")      ["[rel='bookmark']",

"rel", "=", "'", "bookmark", undefined]

4       attr.exec("a[rel=\"bookmark\"]") ["[rel="bookmark"]",

"rel", "=", """, "bookmark",

undefined]

5       attr.exec("a[rel=bookmark]")        ["[rel=bookmark]",

"rel", "=", undefined, undefined, "bookmark"]

6       attr.exec("a[rel='bookmark']")      ["[rel='bookmark']",

7       attr.exec("input[name=foo\\.baz]")      ["[name=foo\\.baz]",

"name", "=", undefined, undefined, "foo\\.baz"]

8       attr.exec("input[name=foo\\[baz\\]]") ["[name=foo\\[baz\\]]",

"name", "=", undefined, undefined, "foo\\

[baz\\]"]

9       attr.exec("a[href='http://www.google.com/']")   ["[href='http://www.google.com/']",

"href", "=", "'",

"http://www.google.com/", undefined]

10     attr.exec("a[href^='http://www']")      ["[href^='http://www']",

"href", "^=", "'", "http://www",

11     attr.exec("a[href$='org/']")  ["[href$='org/']", "href",

"$=", "'", "org/", undefined]

12     attr.exec("a[href*='google']")       ["[href*='google']",

"href", "*=", "'", "google", undefined]

13     attr.exec("option[value='']") ["[value='']", "value",

"=", "'", "", undefined]

14     attr.exec("option[value!='']")        ["[value!='']",

"value", "!=", "'", "", undefined]

15     attr.exec("[xml\\:test]")        ["[xml\\:test]",

"xml\\:test", undefined, undefined, undefined, undefined]

16     attr.exec("[data-foo]")  ["[data-foo]", "data-foo",

圖3-11 正則sizzle.selectors.match.tag

表3-7 正則 sizzle.selectors.match.tag

1       tag.exec("body")    ["body", "body"]

2       tag.exec("html")    ["html", "html"]

3       tag.exec("h1")        ["h1", "h1"]

表3-8  正則

sizzle.selectors.match.child

1       child.exec("p:first-child")      [":first-child",

"first", undefined]

2       child.exec("p:only-child")      [":only-child",

"only", undefined]

3       child.exec("option:nth-child")       [":nth-child", "nth",

4       child.exec("option:nth-child(even)")     [":nth-child(even)",

"nth", "even"]

5       child.exec("option:nth-child(odd)")       [":nth-child(odd)",

"nth", "odd"]

6       child.exec("option:nth-child(1)")  [":nth-child(1)", "nth",

"1"]

7       child.exec("option:nth-child(+1)")         [":nth-child(+1)",

"nth", "+1"]

8       child.exec("option:nth-child(-1)") [":nth-child(-1)", "nth",

"-1"]

9       child.exec("option:nth-child(0n+3)")    [":nth-child(0n+3)",

"nth", "0n+3"]

10     child.exec("option:nth-child(1n)")         [":nth-child(1n)",

"nth", "1n"]

11     child.exec("option:nth-child(n)")  [":nth-child(n)", "nth",

"n"]

12     child.exec("option:nth-child(+n)")         [":nth-child(+n)",

"nth", "+n"]

13     child.exec("option:nth-child(-1n

+ 3)") [":nth-child-1n +

3)", "nth", "-1n + 3"]

14     child.exec("option:nth-child(-n+3)")     [":nth-child(-n+3)",

"nth", "-n+3"]

15     child.exec("option:nth-child(-1n+3)")   [":nth-child(-1n+3)",

"nth", "-1n+3"]

16     child.exec("option:nth-child(2n)")         [":nth-child(2n)",

"nth", "2n"]

17     child.exec("option:nth-child(2n

+ 1)")  [":nth-child(2n+1)",

"nth", "2n+1"]

18     child.exec("option:nth-child(2n

+ 1)")  [":nth-child(2n +

1)", "nth", "2n + 1"]

19     child.exec("option:nth-child(+2n+1)")  [":nth-child(+2n + 1)",

"nth", "+2n + 1"]

20     child.exec("option:nth-child(3n)")         [":nth-child(3n)",

"nth", "3n"]

21     child.exec("option:nth-child(3n+0)")    [":nth-child(3n+0)",

"nth", "3n+0"]

22     child.exec("option:nth-child(3n+1)")    [":nth-child(3n+1)",

"nth", "3n+1"]

23     child.exec("option:nth-child(3n-0)")     [":nth-child(3n-0)",

"nth", "3n-0"]

24     child.exec("option:nth-child(3n-1)")     [":nth-child(3n-1)",

"nth", "3n-1"]

圖3-13 正則sizzle.selectors.match.pos

表3-9 正則 sizzle.selectors.match.pos

1       pos.exec("p:nth(1)")        [":nth(1)", "nth",

2       pos.exec("p:eq(2)")         [":eq(2)", "eq",

"2"]

3       pos.exec("p:gt(3)") [":gt(3)", "gt",

"3"]

4       pos.exec("p:lt(4)")  [":lt(4)", "lt",

"4"]

5       pos.exec("p:first")  [":first", "first",

6       pos.exec("p:last")   [":last", "last",

7       pos.exec("p:even") [":even", "even",

8       pos.exec("p:odd")   [":odd", "odd",

圖3-14 正則 sizzle.selectors.match.pseudo

表3-10  正則 sizzle.selectors.match.pseudo

1       pseudo.exec("p:has(a)")        [":has(a)", "has",

"", "a"]

2       pseudo.exec("a:contains(google)")       [":contains(google)",

"contains", "", "google"]

3       pseudo.exec("input:focus")   [":focus", "focus",

undefined, undefined]

4       pseudo.exec(":input")   [":input", "input",

5       pseudo.exec(":radio")   [":radio", "radio",

6       pseudo.exec(":checkbox")     [":checkbox",

"checkbox", undefined, undefined]

7       pseudo.exec(":text")     [":text", "text",

8       pseudo.exec(":radio:checked")     [":radio", "radio",

9       pseudo.exec(":checkbox:checked")       [":checkbox",

10     pseudo.exec("option:selected")    [":selected",

"selected", undefined, undefined]

11     pseudo.exec(":header")         [":header",

"header", undefined, undefined]

12     pseudo.exec(":empty") [":empty", "empty",

13     pseudo.exec(":parent")          [":parent",

"parent", undefined, undefined]

14     pseudo.exec(":hidden")          [":hidden",

"hidden", undefined, undefined]

15     pseudo.exec(":visible") [":visible", "visible",

3.9.3 sizzle.selectors.find

對象sizzle.selectors.find 中定義了id、class、name、tag所對應的查找函數,稱為“查找函數集”。其中,class需要浏覽器支援方法getelementsbyclassname()。

查找函數會傳回元素集合或 undefined,内部通過調用相應的原生方法來查找元素,如表3-11所示。查找函數調用原生方法前會檢查上下文是否支援原生方法。

表3-11  查找函數集

sizzle.selectors.find

序  号         類型         原 生 方 法  說  明

1       id     getelementbyid()    查找擁有指定id的第一個元素

2       class       getelementsbyclassname()   查獲擁有指定類樣式的元素集合

3       name       getelementsbyname()    查獲擁有指定name的元素集合

4       tag  getelementsbytagname()       查找擁有指定标簽名的元素集合

1.?id

4340    

find: {

4341        

id: function( match, context, isxml ) {

4342             if ( typeof context.getelementbyid

!== "undefined" &amp;&amp; !isxml ) {

4343                 var m =

context.getelementbyid(match[1]);

4344                 // check parentnode to catch

when blackberry 4.6 returns

4345                 // nodes that are no longer in

the document #6963

4346                 return m &amp;&amp; m.parentnode

? [m] : [];

4347             }

4348        

4370    

2.?class

5139 (function(){

// 測試浏覽器是否支援方法 getelementsbyclassname()

// 如果不支援,則不做任何事情

// 如果目前浏覽器支援方法 getelementsbyclassname()

5162    

3.?name

4350        

name: function( match, context ) {

4351             if ( typeof

context.getelementsbyname !== "undefined" ) {

4352                 var ret = [],

4353                     results =

context.getelementsbyname( match[1] );

4354

4355                 for ( var i = 0, l =

results.length; i &lt; l; i++ ) {

4356                     if (

results[i].getattribute("name") === match[1] ) {

4357  

                      ret.push(

results[i] );

4358                     }

4359                 }

4360

4361                 return ret.length === 0 ? null

: ret;

4362             }

4363        

4364

4.?tag

4365        

tag: function( match, context ) {

4366             if ( typeof

context.getelementsbytagname !== "undefined" ) {

4367                 return

context.getelementsbytagname( match[1] );

4368             }

4369        

3.9.4 sizzle.selectors.prefilter

對象sizzle.selectors.prefilter中定義了類型class、id、tag、child、attr、pseudo、pos所對應的預過濾函數,稱為“預過濾函數集”。

在方法sizzle.filter( expr, set, inplace, not )中,預過濾函數在過濾函數sizzle.selectors.filter[

type ]之前被調用,見圖3-6。調用預過濾函數時的參數格式為:

sizzle.selectors.prefilter[ type ]( 正則比對結果 match,

元素集合 curloop, 是否縮小元素集合 inplace, 新集合 result, 是否取反 not, isxml )

預過濾函數用于在過濾函數之前修正與過濾操作相關的參數,每種類型的預過濾函數其修正行為如表3-12所示。

表3-12  預過濾函數集

sizzle.selectors.prefilter

序 号     類 型     修 正 行 為  序 号     類 型     修 正 行 為

1       class       過濾不比對元素,或縮小元素集合     5       attr         修正屬性名和屬性值

2       id     過濾轉義反斜杠     6       pseudo   處理:not( selector )的僞類參數

3       tag  過濾轉義反斜杠,轉為小寫         7       pos  修正位置僞類的參數下标

4       child       格式化子元素僞類參數                           

預過濾函數有3種傳回值,對應的含義如表3-13所示。

表3-13  預過濾函數的傳回值

序  号         返 回 值     說  明

1       false          已經執行過濾,或已經縮小候選集,不需要再執行過濾函數,例如,class

2       true 需要繼續執行其他的預過濾函數,尚不到執行過濾函數的時候,例如,在pseudo預過濾函數中遇到pos、child時

3       其他         可以調用對應的過濾函數

對象sizzle.selectors.prefilter的總體源碼結構如下所示:

var expr = sizzle.selectors = {

prefilter: {

class: function( match, curloop, inplace, result, not, isxml )  { ... },

id: function( match )  { ... },

tag: function( match, curloop )  {

... },

child: function( match )  { ... },

attr: function( match, curloop, inplace, result, not, isxml )  { ... },

pseudo: function( match, curloop, inplace, result, not )  { ... },

pos: function( match )  { ... }

   },

下面對其中的預過濾函數逐個進行介紹和分析。

1.?class

類樣式預過濾函數sizzle.selectors.prefilter.class( match, curloop, inplace, result,

not, isxml )負責檢查元素集合中的每個元素是否含有指定的類樣式。如果參數inplace為true,則将不比對的元素替換為false;如果參數inplace不是true,則将比對元素放入元素集合result中,以此來不斷地縮小元素集合。關于正則sizzle.selectors.match/leftmatch.class的說明請參見3.9.2節。

3866    

rbackslash = /\\/g,

4371    

4372        

class: function( match, curloop, inplace, result, not, isxml ) {

4373             match = " " +

match[1].replace( rbackslash, "" ) + " ";

4374

4375             if ( isxml ) {

4376                 return match;

4377             }

4378

4379  

          for ( var i = 0, elem;

(elem = curloop[i]) != null; i++ ) {

4380                 if ( elem ) {

4381                     if ( not ^ (elem.classname

&amp;&amp; (" " + elem.classname +

" "). replace(/[\t\n\r]/g, "

").indexof(match) &gt;= 0) ) {

4382                         if ( !inplace ) {

4383                             result.push( elem

);

4384                         }

4385

4386                     } else if ( inplace ) {

4387                         curloop[i] = false;

4388                     }

4389  

              }

4390             }

4391

4392             return false;

4393        

4475    

第4373行:檢查類樣式的技巧是在前後加空格,然後用字元串方法indexof()進行判斷。

第4379~4390行:周遊元素集合curloop,檢測每個元素是否含有指定名稱的類樣式;如果參數not不是true,則保留比對元素,并排除不比對元素;如果參數not是true,則保留不比對元素,排除比對元素。如果參數inplace為true,則将不比對的元素替換為false;如果參數inplace不是true,則不修改元素集合curloop,而是将比對元素放入元素集合result中,以此來不斷地縮小元素集合。

第4381~4388行:這段if-else-if語句塊的邏輯有些繞,可以這樣了解:if代碼塊表示的是過濾時通過了的情況,else-if語句塊表示的是過濾時未通過的情況。

第4392行:class預過濾函數總是傳回false,表示已經執行過濾,或已縮小候選集,不需要再執行class過濾函數。

2.?id

id預過濾函數sizzle.selectors.prefilter.id(

match )負責過濾轉義反斜杠,從比對結果match中提取并傳回id值。關于正則sizzle.selectors.match/leftmatch.id的具體說明請參見3.9.2節。

4395        

id: function( match ) {

4396             return match[1].replace(

rbackslash, "" );

4397        

3.?tag

标簽預過濾函數sizzle.selectors.prefilter.tag( match, curloop )負責過濾轉義反斜杠,轉換為小寫,從比對結果match中提取并傳回标簽名。關于正則sizzle.selectors.match/left

match.tag的具體說明參見3.9.2節。

4399        

tag: function( match, curloop ) {

4400             return match[1].replace(

rbackslash, "" ).tolowercase();

4401        

4.?child

子元素僞類預過濾函數sizzle.selectors.prefilter.child( match )負責将僞類:nth-child

( index/even/odd/equation )的參數格式化為first*n

+ last,例如,将odd格式化為2n+1。關于正則sizzle.selectors.match/leftmatch.child的具體說明請參見3.9.2節。

4403        

child: function( match ) {

4404             if ( match[1] === "nth"

) {

4405                 if ( !match[2] ) {

4406                     sizzle.error( match[0] );

4407                 }

4408

4409                 match[2] =

match[2].replace(/^\+|\s*/g, '');

4410

4411                 // parse equations like

'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'

4412                 var test =

/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(

4413                     match[2] ===

"even" &amp;&amp; "2n" ||

                         match[2] ===

"odd" &amp;&amp; "2n+1" ||

4414                     !/\d/.test( match[2] )

&amp;&amp; "0n+" + match[2] ||

                         match[2]);

4415

4416                 // calculate the numbers

(first)n+(last) including if they are negative

4417                 match[2] = (test[1] + (test[2]

|| 1)) - 0;

4418                 match[3] = test[3] - 0;

4419             }

4420             else if ( match[2] ) {

4421                 sizzle.error( match[0] );

4422             }

4423

4424             // todo: move to normal caching

system

4425    

        match[0] = done++;

4426

4427             return match;

4428        

第4409行:替換僞類開頭的加号和包含的空格,例如,:nth-child(+1)→:nth-child(1)、

:nth-child(2n + 1)→:nth-child(2n+1)。

第4412~4414行:将僞類參數統一格式化為first*n + last,例如,even→2n、odd→

2n+1、數字→0n+數字。正則/(-?)(\d*)(?:n([+\-]?\d*))?/含有3個分組:負号、first部分、last部分。

第4417~4418行:計算first部分和last部分。注意減0是為了将字元串強制轉換為數值。

第4425行:為本次過濾配置設定一個唯一的辨別,用于優化過濾過程,請參見3.9.7節對子元素僞類過濾函數sizzle.selectors.filter.child( elem, match )的介紹和分析。

5.?attr

屬性預過濾函數sizzle.selectors.prefilter.attr( match, curloop, inplace, result,

not, isxml )負責修正比對結果match中的屬性名和屬性值。關于正則sizzle.selectors.match/leftmatch.attr的具體說明請參見3.9.2節。

4430        

attr: function( match, curloop, inplace, result, not, isxml ) {

4431             var name = match[1] =

match[1].replace( rbackslash, "" );

4432            

4433             if ( !isxml &amp;&amp;

expr.attrmap[name] ) {

4434                 match[1] = expr.attrmap[name];

4435             }

4436

4437             // handle if an un-quoted value

was used

4438             match[4] = ( match[4] || match[5]

|| "" ).replace( rbackslash, "" );

4439

4440             if ( match[2] === "~=" )

{

4441                 match[4] = " " + match[4] +

" ";

4442             }

4443

4444             return match;

4445        

第4431~4435行:修正屬性名。删除轉義反斜杠,修正某些特殊屬性名。

第4438~4442行:修正屬性值。合并分組4和分組5的值,删除轉義反斜杠。當屬性表達式的屬性值有引号時,屬性值存儲在match[4],否則存儲在match[5]。如果等号部分是~=,表示是單詞比對,則在屬性值前後加空格;在過濾函數中,對于~=,會在元素的屬性值前後加空格,然後用字元串方法indexof()檢查。

6.?pseudo

僞類預過濾函數sizzle.selectors.prefilter.pseudo( match, curloop, inplace, result,

not )主要負責處理僞類表達式是:not( selector )的情況,該函數會将比對結果match中的分組3(即僞類參數selector)替換為與之比對的元素集合;對于位置僞類和子元素僞類,則傳回true,繼續執行各自對應的預過濾函數。關于正則sizzle.selectors.match/leftmatch.pseudo的具體說明請參見3.9.2節。

4447        

pseudo: function( match, curloop, inplace, result, not ) {

4448             if ( match[1] === "not"

4449                 // if we're dealing with a

complex expression, or a simple one

4450                 if ( ( chunker.exec(match[3])

|| "" ).length &gt; 1 || /^\w/.test(match[3]) ) {

4451                     match[3] =

sizzle(match[3], null, null, curloop);

4452

4453                 } else {

4454                     var ret =

sizzle.filter(match[3], curloop, inplace, true ^ not);

4455

4456                     if ( !inplace ) {

4457                         result.push.apply(

result, ret );

4458                     }

4459

4460                     return false;

4461                 }

4462

4463             } else if ( expr.match.pos.test(

match[0] ) || expr.match.child.test( match[0] ) ) {

4464                 return true;

4465             }

4466            

4467             return match;

4468        

第4447行:參數match是正則sizzle.selectors.match.pseudo比對塊表達式的結果,含有3個分組:僞類、引号、僞類參數。

第4448~4461行:如果僞類是:not(selector),則将比對結果match中的分組3(即僞類參數selector)替換為與之其比對的元素集合。在對應的過濾函數中,會篩選出不在分組3中的元素。

第4463~4465行:如果是位置僞類pos或子元素僞類child,則傳回true,表示仍然需要繼續執行各自所對應的預過濾函數。注意,位置僞類pos和子元素僞類child有着自己的預過濾函數。

7.?pos

位置僞類預過濾函數sizzle.selectors.prefilter.pos( match )負責在比對結果match的頭部插入一個新元素true,使得比對結果match中位置僞類參數的下标變為了3,進而與僞類的比對結果保持一緻。關于正則sizzle.selectors.match/leftmatch.pos/pseudo的具體說明請參見3.9.2節。

4470        

pos: function( match ) {

4471             match.unshift( true );

4472

4473             return match;

4474        

3.9.5 sizzle.selectors.filters

對象sizzle.selectors.filters中定義了一組僞類和對應的僞類過濾函數,稱為“僞類過濾函數集”。支援的僞類有::enabled、:disabled、:checked、:selected、:parent、:empty、:has、:header、:text、:radio、:checkbox、:file、:password、:submit、:image、:reset、:button、:input、:focus。方法調用鍊為:sizzle.filter()→sizzle.selectors.filter.pseudo()→sizzle.selectors.filters,如圖3-1所示。

僞類過濾函數負責檢查元素是否比對僞類,傳回一個布爾值,其參數格式為:

sizzle.selectors.filters[ 僞類 ]( 元素, 序号, 正則比對結果, 元素集合 );

// 正則比對結果是正則

sizzle.selectors.match.pseudo 比對塊選擇器表達式的結果,含有 3 個分組:僞類、引号、僞類參數

相關代碼如下所示,為了友善解釋,代碼中增加了示例和注釋:

4477    

filters: {

// $(':enabled') 比對所有可用元素(未禁用的,不隐藏的)

4478        

enabled: function( elem ) {

4479             return elem.disabled === false

&amp;&amp; elem.type !== "hidden";

4480        

4481        

// $(':disabled') 比對所有不可用元素(禁用的)

4482        

disabled: function( elem ) {

4483             return elem.disabled === true;

4484        

4485        

// $(':checked') 比對所有選中的被選中元素,包括複選框、單選按鈕,不包括 option 元素

4486        

checked: function( elem ) {

4487             return elem.checked === true;

4488        

4489        

// $(':selected') 比對所有選中的 option 元素

4490  

      selected: function( elem ) {

4491             // accessing this property makes

selected-by-default

4492             // options in safari work properly

4493             if ( elem.parentnode ) {

4494                 elem.parentnode.selectedindex;

4495             }

4496            

4497             return elem.selected === true;

4498        

4499        

// $(':parent') 比對所有含有子元素或文本的元素

4500        

parent: function( elem ) {

4501             return !!elem.firstchild;

4502        

4503        

// $(':empty') 比對所有不包含子元素或者文本的空元素

4504        

empty: function( elem ) {

4505             return !elem.firstchild;

4506        

4507        

// $(':has(selector)') 比對含有選擇器所比對元素的元素

4508        

has: function( elem, i, match ) {

4509             return !!sizzle( match[3], elem

).length;

4510        

4511        

// $(':header') 比對如 h1、h2、h3 之類的标題元素

4512        

header: function( elem ) {

4513             return (/h\d/i).test(

elem.nodename );

4514        

4515        

// $(':text') 比對所有單行文本框

4516        

text: function( elem ) {

4517             var attr = elem.getattribute(

"type" ), type = elem.type;

4518             // ie6 and 7 will map elem.type to

'text' for new html5 types (search, etc)

4519             // use getattribute instead to

test this case

4520             return elem.nodename.tolowercase()

=== "input" &amp;&amp; "text" === type &amp;&amp; ( attr

=== type || attr === null );

4521        

4522        

// $(':radio') 比對所有單選按鈕

4523        

radio: function( elem ) {

4524     

       return

elem.nodename.tolowercase() === "input" &amp;&amp; "radio"

=== elem.type;

4525        

4526        

// $(':checkbox') 比對所有複選框

4527        

checkbox: function( elem ) {

4528             return elem.nodename.tolowercase()

=== "input" &amp;&amp; "checkbox" === elem.type;

4529        

4530        

// $(':file') 比對所有檔案域

4531        

file: function( elem ) {

4532             return elem.nodename.tolowercase()

=== "input" &amp;&amp; "file" === elem.type;

4533        

4534        

// $(':password') 比對所有密碼框

4535        

password: function( elem ) {

4536             return elem.nodename.tolowercase()

=== "input" &amp;&amp; "password" === elem.type;

4537        

4538        

// $(':submit') 比對所有送出按鈕

4539        

submit: function( elem ) {

4540             var name =

elem.nodename.tolowercase();

4541             return (name === "input"

|| name === "button") &amp;&amp; "submit" === elem.type;

4542        

4543        

// $(':image') 比對所有圖像域

4544        

image: function( elem ) {

4545             return elem.nodename.tolowercase()

=== "input" &amp;&amp; "image" === elem.type;

4546        

4547        

// $(':reset') 比對所有重置按鈕

4548        

reset: function( elem ) {

4549             var name =

4550             return (name === "input"

|| name === "button") &amp;&amp; "reset" === elem.type;

4551        

4552        

// $(':button') 比對所有按鈕

4553        

button: function( elem ) {

4554             var name =

4555             return name === "input"

&amp;&amp; "button" === elem.type || name === "button";

4556        

4557        

// $(':input') 比對所有 input、textarea、select、button 元素

4558        

input: function( elem ) {

4559             return

(/input|select|textarea|button/i).test( elem.nodename );

4560        

4561        

// $(':focus') 比對目前焦點元素

4562        

focus: function( elem ) {

4563             return elem ===

elem.ownerdocument.activeelement;

4564        

4565    

3.9.6 sizzle.selectors.setfilters

對象sizzle.selectors.setfilters中定義了一組位置僞類和對應的僞類過濾函數,稱為“位置僞類過濾函數集”。支援的位置僞類有::first、:last、:even、:odd、:lt(index)、:gt(index)、:nth(index)、

:eq(index)。方法調用鍊為:sizzle.filter()→sizzle.selectors.filter.pos()→sizzle.selectors.setfilters,如圖3-1所示。

位置僞類過濾函數通過比較下标來确定元素在集合中的位置,傳回一個布爾值,其參數格式為:

sizzle.selectors.setfilters[ 位置僞類 ]( 元素, 下标, 正則比對結果, 元素集合 );

sizzle.selectors.match.pos 比對塊選擇器表達式的結果,含有 2 個分組:位置僞類、位置僞類參數

4566    

setfilters: {

   // $(':first') 比對找到的第一個元素

4567          first: function( elem, i ) {

4568              return i === 0;

4569          },

4570          // $(':last') 比對找到的最後一個元素

4571          last: function( elem, i, match, array

4572              return i === array.length - 1;

4573          },

4574          // $(':even') 比對所有下标為偶數的元素,從0開始計數

4575          even: function( elem, i ) {

4576              return i % 2 === 0;

4577          },

4578          // $(':odd') 比對所有下标為奇數的元素,從0開始計數

4579          odd: function( elem, i ) {

4580              return i % 2 === 1;

4581          },

4582          // $(':lt(index)') 比對所有小于指定下标的元素

4583          lt: function( elem, i, match ) {

4584              return i &lt; match[3] - 0;

4585          },

4586          // $(':gt(index)') 比對所有大于指定下标的元素

4587          gt: function( elem, i, match ) {

4588              return i &gt; match[3] - 0;

4589          },

4590          // $(':nth(index)') 比對一個指定下标的元素,從

0 開始計數

4591          nth: function( elem, i, match ) {

4592              return match[3] - 0 === i;

4593          },

4594          // $(':eq(index)') 比對一個指定下标的元素,從

4595          eq: function( elem, i, match ) {

4596              return match[3] - 0 === i;

4597          }

4598     

3.9.7 sizzle.selectors.filter

對象sizzle.selectors.filter中定義了類型pseudo、child、id、tag、class、attr、pos所對應的過濾函數,稱為“過濾函數集”。方法調用鍊為:sizzle.filter()→sizzle.selectors.filter[ type ],如圖3-1和圖3-6所示。

過濾函數負責檢查元素是否比對過濾表達式,傳回一個布爾值,其參數格式為:

sizzle.selectors.filter[ 類型 ]( 元素, 正則比對結果或過濾表達式,

下标, 元素集合 )

// 正則比對結果指

sizzle.selectors.match 中對應的正則比對塊表達式的結果

// 過濾表達式指經過

sizzle.selectors.prefilter 處理後的塊表達式

sizzle.selectors.filter的總體源碼結構如下所示:

filter: {

pseudo: function( elem, match, i, array )  { ... },

child: function( elem, match )  {

id: function( elem, match )  { ...

tag: function( elem, match )  {

class: function( elem, match )  {

attr: function( elem, match )  {

pos: function( elem, match, i, array ) 

{ ... }

   }

下面對其中的過濾函數逐個進行介紹和分析。

1.?pseudo

僞類過濾函數sizzle.selectors.filter.pseudo( elem, match, i, array )用于檢查元素是否比對僞類。大部分檢查通過調用僞類過濾函數集sizzle.selectors.filters中對應的僞類過濾函數來實作,對于僞類:contains(text)、:not(selector)則做特殊處理。具體請參見3.9.5節。

4599    

4600        

pseudo: function( elem, match, i, array ) {

4601             var name = match[1],

4602                 filter = expr.filters[ name ];

4603

4604             if ( filter ) {

4605                 return filter( elem, i, match, array );

4606

4607             } else if ( name ===

"contains" ) {

4608                 return (elem.textcontent ||

elem.innertext || gettext([ elem ]) || "").indexof(match[3]) &gt; =

0;

4609

4610             } else if ( name ===

"not" ) {

4611                 var not = match[3];

4612

4613                 for ( var j = 0, l =

not.length; j &lt; l; j++ ) {

4614                     if ( not[j] === elem ) {

4615                         return false;

4616                     }

4617                 }

4618

4619                 return true;

4620

4621             } else {

4622                 sizzle.error( name );

4623             }

4624        

4748    

第4600行:參數match是正則sizzle.selectors.match.pseudo比對塊表達式的結果,含有3個分組:僞類、引号、僞類參數。

第4602~4605行:如果在僞類過濾函數集sizzle.selectors.filters中存在對應的僞類過濾函數,則調用它來檢查元素是否比對僞類。

第4607~4608行:僞類:contains(text)用于比對包含指定文本的所有元素。如果僞類是:contains( text ),則先取出目前元素的文本内容,然後調用字元串方法indexof()檢查是否含有指定的文本。

第4610~4619行:僞類:not(selector)用于比對與指定選擇器不比對的所有元素。如果僞類是:not(selector),則檢查目前元素是否與match[3]中的某個元素相等,如果相等則傳回false,否則傳回true。在預過濾函數sizzle.selectors.prefilter.pseudo中,對于僞類:not

(selector),會将match[3]替換為其比對的元素集合。

第4621~4623行:對于不支援的僞類,一律調用方法sizzle.error( msg )抛出文法錯誤。方法sizzle.error( msg )請參見3.10.4節。

2.?child

子元素僞類過濾函數sizzle.selectors.filter.child( elem, match )用于檢查元素是否比對子元素僞類。支援的子元素僞類如表3-14所示。

表3-14 子元素僞類

序  号         子元素僞類     說  明

1       :nth-child(index/even/odd/equation)       比對父元素下的第n個子元素或奇偶元素

2       :first-child         比對父元素的第一個子元素

3       :last-child          比對父元素的最後一個子元素

4       :only-child         如果某個元素是父元素的唯一子元素,則比對;如果父元素還含有多個子元素,則不比對

4626        

child: function( elem, match ) {

4627             var first, last,

4628                 donename, parent, cache,

4629  

              count, diff,

4630                 type = match[1],

4631                 node = elem;

4632

4633             switch ( type ) {

4634                 case "only":

4635                 case "first":

4636                     while ( (node = node.previoussibling)

)  {

4637                         if ( node.nodetype ===

1 ) {

4638                             return false;

4639                         }

4640                     }

4641

4642                     if ( type ===

"first" ) {

4643       

                 return true;

4644                     }

4645

4646                     node = elem;

4647

4648                 case "last":

4649                     while ( (node =

node.nextsibling) )  {

4650                         if ( node.nodetype ===

4651                             return false;

4652                         }

4653                     }

4654

4655                     return true;

4656

4657                 case "nth":

4658   

                 first = match[2];

4659                     last = match[3];

4660

4661                     if ( first === 1

&amp;&amp; last === 0 ) {

4662                         return true;

4663                     }

4664                    

4665                     donename = match[0];

4666                     parent = elem.parentnode;

4667    

4668                     if ( parent &amp;&amp;

(parent[ expando ] !== donename || !elem.nodeindex) ) {

4669                         count = 0;

4670                        

4671                         for ( node =

parent.firstchild; node; node = node.nextsibling ) {

4672                             if ( node.nodetype

=== 1 ) {

4673                                 node.nodeindex

= ++count;

4674                             }

4675                         }

4676

4677                         parent[ expando ] =

donename;

4678                     }

4679                    

4680                     diff = elem.nodeindex -

last;

4681

4682                     if ( first === 0 ) {

4683                         return diff === 0;

4684

4685                     } else {

4686                         return ( diff % first

=== 0 &amp;&amp; diff / first &gt;= 0 );

4687                     }

4688             }

4689        

第4634~4655行:如果僞類是:only-child,則檢查目前元素之前(previoussibling)和之後(nextsibling)是否有兄弟元素,如果都沒有則傳回true,否則傳回false。注意這裡的分支only是通過分支first和分支last實作的。

第4635~4644行:如果僞類是:first-child,則檢查目前元素之前(previoussibling)是否有兄弟元素,有則傳回false,沒有則傳回true。

第4648~4655行:如果僞類是:last-child,則檢查目前元素之後(nextsibling)是否有兄弟元素,有則傳回false,沒有則傳回true。

第4657~4687行:如果僞類是:nth-child(index/even/odd/equation),則檢查目前元素的下标是否比對僞類參數,檢測公式為:

( 目前元素在其父元素中的下标位置 -

last ) % first === 0

在預過濾函數sizzle.selectors.prefilter.child中已将僞類參數統一格式化為first*n+last,例如,odd格式化為2n+1,其中,first存儲在match[2]中,last存儲在match[3]中。

第4665~4678行:找到目前元素的父元素,然後為每個子元素設定屬性nodeindex,進而辨別出每個子元素的下标位置。如果父元素未被本次過濾辨別過,或目前元素未被辨別過,才會為子元素設定屬性nodeindex,以確定隻會辨別一次。

match[0]是本次過濾的唯一辨別,在執行子元素預過濾函數sizzle.selectors.prefilter.child( match )時被配置設定,具體請參見3.9.4節。

id過濾函數sizzle.selectors.filter.id(

elem, match )用于檢查元素的屬性id是否與指定的id相等。

4691        

id: function( elem, match ) {

4692             return elem.nodetype === 1

&amp;&amp; elem.getattribute("id") === match;

4693        

标簽過濾函數sizzle.selectors.filter.tag( elem, match )用于檢查元素的标簽名nodename是否與指定的标簽名相等。

5.?class

類樣式過濾函數sizzle.selectors.filter.class( elem, match )用于檢查元素的類樣式classname是否含有指定的類樣式。檢查技巧是在類樣式前後加空格,然後判斷字元串方法indexof()的傳回值。

4221 var expr = sizzle.selectors

= {

4699        

class: function( elem, match ) {

4700             return (" " +

(elem.classname || elem.getattribute("class")) + " ")

4701                 .indexof( match ) &gt; -1;

4702        

6.attr

屬性過濾函數sizzle.selectors.filter.attr( elem, match )用于檢查元素的屬性是否比對屬性表達式。支援的屬性表達式如表3-15所示。

表3-15 屬性表達式

序  号         屬性表達式     說  明

1       [attribute]        比對含有指定屬性的元素

2       [attribute=value]     比對含有指定屬性,并且目前屬性值等于指定值的元素

3       [attribute!=value]    比對不包含指定屬性,或者目前屬性值不等于指定值的元素

4       [attribute^=value]   比對含有指定屬性,并且屬性值以指定值開始的元素

5       [attribute$=value]   比對含有指定屬性,并且目前屬性值以指定值結束的元素

6       [attribute*=value]   比對含有指定屬性,并且目前屬性值包含指定值的元素

7       [attribute|="value"]         比對含有指定屬性,并且目前屬性值等于指定值,或者目前屬性值以指定值開頭,并且後跟一個連字元(-)的元素

8       [attribute~="value"]        比對含有指定屬性,并且目前屬性值含有指定單詞的元素。單詞之間用空格分隔

4704        

attr: function( elem, match ) {

4705             var name = match[1],

4706                 result = sizzle.attr ?

4707                     sizzle.attr( elem, name )

:

4708                     expr.attrhandle[ name ] ?

4709                     expr.attrhandle[ name ](

elem ) :

4710                     elem[ name ] != null ?

4711                         elem[ name ] :

4712                         elem.getattribute(

name ),

4713                 value = result + "",

4714                 type = match[2],

4715                 check = match[4];

4716

4717             return result == null ?

4718                 type === "!=" :

4719                 !type &amp;&amp; sizzle.attr ?

4720  

              result != null :

4721                 type === "=" ?

4722                 value === check :

4723                 type === "*=" ?

4724                 value.indexof(check) &gt;= 0 :

4725                 type === "~=" ?

4726                 (" " + value +

" ").indexof(check) &gt;= 0 :

4727                 !check ?

4728                 value &amp;&amp; result !==

false :

4729                 type === "!=" ?

4730                 value !== check :

4731                 type === "^=" ?

4732                 value.indexof(check) === 0 :

4733                 type === "$=" ?

4734                 value.substr(value.length -

check.length) === check :

4735                 type === "|=" ?

4736                 value === check ||

value.substr(0, check.length + 1) === check + "-" :

4737                 false;

4738        

第4705行:變量name是指定的屬性名。

第4706~4712行:變量result是元素的html屬性值或dom屬性值。在jquery中,因為sizzle.attr()等價于jquery.attr(),是以總是傳回html屬性,是以變量result也總是html屬性值;在獨立使用sizzle時,則是先嘗試讀取dom屬性值,如果不存在才會讀取html屬性值。

第4713~4715行:變量value是變量result字元串格式;變量type是屬性表達式的等号部分,例如,=、!=;變量check是指定的屬性值。

第4717~4737行:根據等号部分,采用不同的比較方式來檢查元素是否比對屬性表達式。由于這段複合三元表達式太長太複雜,是以,下面将格式稍做調整并加上注釋,以便于閱讀了解:

// [name!=value] 不包含指定屬性

return result == null ? type ===

"!=" :

   //

[name] 包含指定屬性

!type &amp;&amp; sizzle.attr ? result != null :

[name=check] 包含指定屬性,屬性值等于指定值

type === "=" ? value === check :

[name*=check] 含有指定屬性,屬性值包含指定值

type === "*=" ? value.indexof(check) &gt;= 0 :

[name~="value"] 含有指定屬性,屬性值含有指定單詞

type === "~=" ? (" " + value + "

").indexof(check) &gt;= 0 :

如果沒有指定值 check,隻有指定屬性值,并且屬性值不是 false,才會傳回 true

!check ? value &amp;&amp; result !== false :

以下均有指定值 check

[name!=check] 含有指定屬性,屬性值不等于指定值

type === "!=" ? value !== check :

[name^=check] 含有指定屬性,屬性值以指定值開始

type === "^=" ? value.indexof(check) === 0 :

[name$=check] 含有指定屬性,屬性值以指定值結束

type === "$=" ? value.substr(value.length - check.length) ===

check :

[name|=check] 含有指定屬性,屬性值等于指定值,或者以指定值開頭,且後跟一個連字元(-)

type === "|=" ? value === check || value.substr(0,

check.length + 1) === check + "-" :

false;

位置僞類過濾函數sizzle.selectors.filter.pos( elem, match, i, array )用于檢查元素是否比對位置僞類,該函數通過調用位置僞類過濾函數集sizzle.selectors.setfilters中對應的位置僞類過濾函數來實作,具體請參見3.9.6節。調用關系如圖3-1所示。

4740      

pos: function( elem, match, i, array ) {

4741          var name = match[2],

4742             filter = expr.setfilters[ name ];

4743

4744          if ( filter ) {

4745             return filter( elem, i, match,

array );

4746          }

4747     

4748   

繼續閱讀