jQuery原始碼分析之select()方法
本章節對jQuery原始碼中的select()實現進行一下分析。
分析文字在原始碼中,以註釋的形式存在,感興趣的朋友可以做一下參考。
程式碼如下:
[JavaScript] 純文字檢視 複製程式碼/* * select方法是Sizzle選擇器包的核心方法之一,其主要完成下列任務: * 1、呼叫tokenize方法完成對選擇器的解析 * 2、對於沒有初始集合(即seed沒有賦值)且是單一塊選擇器(即選擇器字串中沒有逗號), * 完成下列事項: * 1) 對於首選擇器是ID型別且context是document的,則直接獲取物件替代傳入的context物件 * 2) 若選擇器是單一選擇器,且是id、class、tag型別的,則直接獲取並返回匹配的DOM元素 * 3) 獲取最後一個id、class、tag型別選擇器的匹配DOM元素賦值給初始集合(即seed變數) * 3、通過呼叫compile方法獲取“預編譯”程式碼並執行,獲取並返回匹配的DOM元素 * * @param selector 已去掉頭尾空白的選擇器字串 * @param context 執行匹配的最初的上下文(即DOM元素集合)。若context沒有賦值,則取document。 * @param results 已匹配出的部分最終結果。若results沒有賦值,則賦予空陣列。 * @param seed 初始集合 */ function select(selector, context, results, seed) { var i, tokens, token, type, find, // 呼叫tokenize函式解析selector match = tokenize(selector); // 若沒有提供初始集合 if (!seed) { // Try to minimize operations if there is only one group // 若只有一組選擇器,即選擇器字串沒有逗號 if (match.length === 1) { // Take a shortcut and set the context if the root selector // is an ID /* * 下面程式碼是用來處理根選擇器是ID型別的快捷方式 * * 在此使用slice[0]來建立一個新的集合, * 確保原有的集合不會被之後程式碼變更掉 */ tokens = match[0] = match[0].slice(0); /* * 若選擇器是以id型別開始,且第二個是關係符(即+~>或空格), * 則獲取id所屬物件作為context繼續完成後續的匹配 * * 此處的條件判斷依次為: * tokens.length > 2 :若tokens有兩個以上的選擇器 * (token = tokens[0]).type === "ID" :第一個選擇器的型別為ID(即以#開頭的), * support.getById :支援getElementById函式 * context.nodeType === 9 :context物件是document * documentIsHTML :當前處理的是HTML程式碼 * Expr.relative[tokens[1].type] :第二個tokens元素是一個關係(即+~>或空格) * 在滿足上面所有條件的情況下,執行if內的語句體 */ if (tokens.length > 2 && (token = tokens[0]).type === "ID" && support.getById && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) { // 將當前上下文指向第一個ID選擇器指定的節點物件 context = (Expr.find["ID"](token.matches[0].replace( runescape, funescape), context) || [])[0]; // 若當前上下文內沒有指定ID物件,則直接返回results if (!context) { return results; } // 選擇器字串去掉第一個ID選擇器 selector = selector.slice(tokens.shift().value.length); } // Fetch a seed set for right-to-left matching /* * 下面while迴圈的作用是用來根據最後一個id、class、tag型別的選擇器獲取初始集合 * 舉個簡單例子:若選擇器是"div[title='2']", * 程式碼根據div獲取出所有的context下的div節點,並把這個集合賦給seed變數, * 然後在呼叫compile函式,產生預編譯程式碼, * 預編譯程式碼完成在上述初始集合中執行[title='2']的匹配 * * 首先,檢查選擇器字串中是否存在與needsContext正規表示式相匹配的字元 * 若沒有,則將依據選擇器從右到左過濾DOM節點 * 否則,將先生成預編譯程式碼後執行(呼叫compile方法)。 */ /* * "needsContext" : new RegExp("^" + whitespace * + "*[>+~]|<img src="static/image/smiley/default/sad.gif" smilieid="2" border="0" alt="">even|odd|eq|gt|lt|nth|first|last)(?:\\(" * + whitespace + "*((?:-\\d)?\\d*)" + whitespace * + "*\\)|)(?=[^-]|$)", "i") * needsContext用來匹配選擇器字串中是否包含下列內容: * 1、>+~三種關係符 * 2、:even、<img src="static/image/smiley/default/shocked.gif" smilieid="6" border="0" alt="">dd、:eq、:gt、:lt、:nth、:first、:last八種偽類 * 其中,(?=[^-]|$)用來過濾掉類似於:first-child等帶中槓的且以上述八個單詞開頭的其它選擇器 */ i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length; while (i--) { token = tokens[i]; // Abort if we hit a combinator // 遇到關係符跳出迴圈 if (Expr.relative[(type = token.type)]) { break; } if ((find = Expr.find[type])) { // Search, expanding context for leading sibling // combinators /* * rsibling = new RegExp(whitespace + "*[+~]") * rsibling用於判定token選擇器是否是兄弟關係符 */ if ((seed = find(token.matches[0].replace( runescape, funescape), rsibling .test(tokens[0].type) && context.parentNode || context))) { // If seed is empty or no tokens remain, we can // return early // 剔除剛用過的選擇器 tokens.splice(i, 1); selector = seed.length && toSelector(tokens); /* * 若selector為空,說明選擇器僅為單一id、class、tag型別的, * 故直接返回獲取的結果,否則,在獲取seed的基礎上繼續匹配 */ if (!selector) { push.apply(results, seed); return results; } break; } } } } } // Compile and execute a filtering function // Provide `match` to avoid retokenization if we modified the // selector above /* * 先執行compile(selector, match),它會返回一個“預編譯”函式, * 然後呼叫該函式獲取最後匹配結果 */ compile(selector, match)(seed, context, !documentIsHTML, results, rsibling.test(selector)); return results; }
相關文章
- 【Java】NIO中Selector的select方法原始碼分析Java原始碼
- Shading – jdbc 原始碼分析(三) – sql 解析之 SelectJDBC原始碼SQL
- jQuery原始碼分析jQuery原始碼
- jQuery2.0.3原始碼分析jQuery原始碼
- jQuery原始碼解析之position()jQuery原始碼
- jQuery原始碼解析之clone()jQuery原始碼
- jQuery原始碼學習之$()jQuery原始碼
- jQuery原始碼解析之replaceWith()/unwrap()jQuery原始碼
- jQuery原始碼學習之eventjQuery原始碼
- jQuery原始碼學習之extendjQuery原始碼
- Vue-Router原始碼分析之install方法Vue原始碼
- jQuery原始碼剖析(三) - Callbacks 原理分析jQuery原始碼
- Android 原始碼分析之 AsyncTask 原始碼分析Android原始碼
- Guava 原始碼分析之 EventBus 原始碼分析Guava原始碼
- jQuery原始碼分析系列 : 整體架構jQuery原始碼架構
- ArrayList方法原始碼分析原始碼
- 原始碼分析之 HashMap原始碼HashMap
- 原始碼分析之 LinkedList原始碼
- Element原始碼分析系列7-Select(下拉選擇框)原始碼
- 原始碼|jdk原始碼之HashMap分析(一)原始碼JDKHashMap
- 原始碼|jdk原始碼之HashMap分析(二)原始碼JDKHashMap
- JQuery select選中值jQuery
- 死磕 jdk原始碼之HashMap原始碼分析JDK原始碼HashMap
- Android 原始碼分析之 EventBus 的原始碼解析Android原始碼
- jquery中on方法原理分析jQuery
- Spring AOP之原始碼分析Spring原始碼
- DRF之Response原始碼分析原始碼
- Redux原始碼分析之createStoreRedux原始碼
- MongoDB原始碼分析之MongosXFMongoDB原始碼
- BlueStore原始碼分析之FreelistManager原始碼
- JUC之ReentrantLock原始碼分析ReentrantLock原始碼
- JUC之CountDownLatch原始碼分析CountDownLatch原始碼
- Flutter原始碼分析之InheritedWidgetFlutter原始碼
- lodash原始碼分析之isArguments原始碼
- Envoy原始碼分析之Dispatcher原始碼
- Fresco原始碼分析之DraweeView原始碼View
- Netty原始碼分析之LengthFieldBasedFrameDecoderNetty原始碼
- RecyclerView之SnapHelper原始碼分析View原始碼
- tornado 原始碼之 coroutine 分析原始碼