jQuery選擇器源碼解讀(四):tokenize方法的Expr.preFilter
更新時間:2015年03月31日 10:44:18 作者:mole
這篇文章主要介紹了jQuery選擇器源碼解讀(四):tokenize方法的Expr.preFilter,本文用詳細的注釋解讀了tokenize方法的Expr.preFilter的實現源碼,需要的朋友可以參考下
Expr.preFilter是tokenize方法中對ATTR、CHILD、PSEUDO三種選擇器進行預處理的方法。具體如下:
Expr.preFilter : {
"ATTR" : function(match) {
/*
* 完成如下任務:
* 1、屬性名稱解碼
* 2、屬性值解碼
* 3、若判斷符為~=,則在屬性值兩邊加上空格
* 4、返回最終的mtach對象
*
* match[1]表示屬性名稱,
* match[1].replace(runescape, funescape):將屬性名稱中的十六進制數解碼成
* 單字節(jié)unicode字符或雙字節(jié)unicode字符(中文或其它需要兩個字節(jié)表達的文字)
* 正則表達式的詳細說明,可以參看我的“詳解jQuery選擇器正則表達式”文章
*/
match[1] = match[1].replace(runescape, funescape);
/*
* 將屬性值解碼
* match[4]:表示放在單引號或雙引號內的屬性值
* match[5]: 表示不用引號括起來的屬性值
*/
match[3] = (match[4] || match[5] || "").replace(runescape,
funescape);
/*
* ~=的意思是單詞匹配,在W3C中對單詞的定義是以空白為不同單詞的分隔符
* 故此處在match[3]兩邊加上空格后,可以利用indexOf,正確識別出該單詞是否存在
*/
if (match[2] === "~=") {
match[3] = " " + match[3] + " ";
}
/*
* 返回有用的前四個元素結果
*/
return match.slice(0, 4);
},
"CHILD" : function(match) {
/*
* 完成如下幾項任務:
* 1、把命令中child和of-type之前的字符變成小寫字符
* 2、對于nth開頭的選擇器檢查括號內的數據有效性
* 3、match[4]和match[5]分別存放xn+b中的x和b,x和b允許是負數
* 4、返回最終的match對象
*
* match[1]:(only|first|last|nth|nth-last)中的一個
*/
match[1] = match[1].toLowerCase();
/*
* 對于nth-child、nth-of-type、nth-last-child、nth-last-of-type四種類型括號內需設置有效數據
* 而其它則括號內不允許有任何數據
*/
if (match[1].slice(0, 3) === "nth") {
/*
* 若選擇器括號內沒有有效參數,則拋出異常
* 舉例:若選擇器是nth或nth(abc)則屬于非法選擇器
*/
if (!match[3]) {
Sizzle.error(match[0]);
}
/*
* 下面先以nth-child()為例介紹一下語法,以便更好的理解下面代碼的作用
* nth-child允許的幾種使用方式如下:
* :nth-child(even)
* :nth-child(odd)
* :nth-child(3n)
* :nth-child(+2n+1)
* :nth-child(2n-1)
* 下面代碼中賦值號左側的match[4]、match[5]用于分別記錄括號內n前及n后的數值,包括正負號
* 對于:nth-child(even)和:nth-child(odd)來說,match[4]為空,
* 所以返回 2 * (match[3] === "even" || match[3] === "odd")的計算結果
* 因為在js中true=1,false=0,所以(match[3] === "even" || match[3] === "odd")等于1
* 因此,2 * (match[3] === "even" || match[3] === "odd")的計算結果為2
*
* 等號右側的“+”的作用是強制類型轉換,將之后的字符串轉換成數值類型
*/
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]) {
/*
* 若非nth起頭的其它CHILD類型選擇器帶有括號說明,則拋出異常
* 這里jQuery并沒有嚴格按照W3C的規(guī)則來判定,因為其允許:first-child()的這種形式存在
* 也就是對于jQuery來說:first-child()等同于:first-child,是合法選擇器
*/
Sizzle.error(match[0]);
}
return match;
},
"PSEUDO" : function(match) {
/*
* 完成如下任務:
* 1、獲取偽類中用引號括起來的值
* 2、對于非引號括起來的值,若存在偽類嵌套,則進一步解析確定當前偽類實際結束位置,
* 獲取當前偽類的完整字符串和值
* 3、返回match中的前三項的副本。
*
* unquoted表示括號內非引號括起來的值,
* 以:eq(2)為例,unquoted=2
*/
var excess, unquoted = !match[5] && match[2];
/*
* 因為pseudo與child的匹配正則表達式有交集,所以,需要把屬于child的部分忽略掉
*/
if (matchExpr["CHILD"].test(match[0])) {
return null;
}
/*
* 若括號內的值使用引號(match[3])括起來的,
* 則將除引號外的值(match[4])賦給match[2]。
* match[3]表示引號。
*/
if (match[3] && match[4] !== undefined) {
match[2] = match[4];
} else if (unquoted
/*
* rpseudo.test(unquoted):用來測試unquoted是否包含偽類,
* 若包含偽類,則說明有可能存在偽類嵌套的可能性,需要進一步對unquoted進行解析
* 例如: :not(:eq(3))
*/
&& rpseudo.test(unquoted)
&&
/*
* 獲取unquoted中連續(xù)有效地選擇器最后一個字符所在位置
*/
(excess = tokenize(unquoted, true))
&&
/*
* unquoted.indexOf(")", unquoted.length - excess)
* 從之前獲得的連續(xù)有效地選擇器最后一個字符所在位置之后找到")"所在位置,
* 通常就在當前位置之后。
* 再減去unquoted.length,用來獲得match[0]中的有效完整的偽類字符串最后位置,
* 注意,此時excess是一個負值
*
*/
(excess = unquoted.indexOf(")", unquoted.length
- excess)
- unquoted.length)) {
// 獲取有效的完整偽類match[0]和偽類括號內的數據match[2]
match[0] = match[0].slice(0, excess);
match[2] = unquoted.slice(0, excess);
}
// 返回match前三個元素的副本
return match.slice(0, 3);
}
}
相關文章
jQuery+Ajax+js實現請求json格式數據并渲染到html頁面操作示例
這篇文章主要介紹了jQuery+Ajax+js實現請求json格式數據并渲染到html頁面操作,結合實例形式分析了jQuery+Ajax請求json格式數據并渲染到html頁面相關步驟與操作技巧,需要的朋友可以參考下2020-06-06

