<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [toc] ## select 函數 前面已經介紹了 tokensize 函數的功能,已經生成了一個 tokens 數組,而且對它的組成我們也做了介紹,下面就是介紹對這個 tokens 數組如何處理。 DOM 元素之間的連接關系大概有 > + ~ 幾種,包括空格,而 tokens 數組中是 type 是有 tag、attr 和連接符之分的,區分它們 Sizzle 也是有一套規則的,比如上一章我們所講的 Expr 對象,它真的非常重要: ``` Expr.relative = { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }; ``` Expr.relative 標記用來將連接符區分,對其種類又根據目錄進行劃分。 現在我們再來理一理 tokens 數組,這個數組目前是一個多重數組,現在不考慮逗號的情況,暫定只有一個分支。如果我們使用從右向左的匹配方式的話,div > div.seq h2 ~ p,會先得到 type 為 TAG 的 token,而對于 type 為 ~ 的 token 我們已經可以用 relative 對象來判斷,現在來介紹 Expr.find 對象: ``` Expr.find = {}; Expr.find['ID'] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var elem = context.getElementById( id ); return elem ? [ elem ] : []; } }; Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { return context.getElementsByClassName( className ); } }; Expr.find["TAG"] = function(){...}; ``` 實際上 jQuery 的源碼還考慮到了兼容性,這里以 `find["ID"]` 介紹: ``` if(support.getById){ Expr.find['ID'] = function(){...}; // 上面 }else{ // 兼容 IE 6、7 Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { var node, i, elems, elem = context.getElementById( id ); if ( elem ) { // Verify the id attribute node = elem.getAttributeNode("id"); if ( node && node.value === id ) { return [ elem ]; } // Fall back on getElementsByName elems = context.getElementsByName( id ); i = 0; while ( (elem = elems[i++]) ) { node = elem.getAttributeNode("id"); if ( node && node.value === id ) { return [ elem ]; } } } return []; } }; } ``` 可以對 find 對象進行簡化: ``` Expr.find = { "ID": document.getElementById, "CLASS": document.getElementsByClassName, "TAG": document.getElementsByTagName } ``` 以后還會介紹 Expr.filter。 ## select 源碼 源碼之前,來看幾個正則表達式。 ``` var runescape = /\\([\da-f]{1,6}[\x20\t\r\n\f]?|([\x20\t\r\n\f])|.)/gi //這個正則是用來對轉義字符特殊處理,帶個反斜杠的 token runescape.exec('\\ab'); //["\ab", "ab", undefined] var rsibling = /[+~]/; //匹配 +、~ matchExpr['needsContext'] = /^[\x20\t\r\n\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\([\x20\t\r\n\f]*((?:-\d)?\d*)[\x20\t\r\n\f]*\)|)(?=[^-]|$)/i //needsContext 用來匹配不完整的 selector matchExpr['needsContext'].test(' + p')//true matchExpr['needsContext'].test(':first-child p')//true //這個不完整,可能是由于抽調 #ID 導致的 ``` 而對于 runescape 正則,往往都是配合 replace 來使用: ``` var str = '\\ab'; str.replace(runescape, funescape); var funescape = function (_, escaped, escapedWhitespace) { var high = "0x" + escaped - 0x10000; // NaN means non-codepoint // Support: Firefox<24 // Workaround erroneous numeric interpretation of +"0x" return high !== high || escapedWhitespace ? escaped : high < 0 ? // BMP codepoint String.fromCharCode(high + 0x10000) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode(high >> 10 | 0xD800, high & 0x3FF | 0xDC00); } ``` 我完全看不懂啦,你們自己意會去吧,O(∩_∩)O哈哈~ ``` var select = Sizzle.select = function (selector, context, results, seed) { var i, tokens, token, type, find, compiled = typeof selector === "function" && selector, match = !seed && tokenize((selector = compiled.selector || selector)); results = results || []; // 長度為 1,即表示沒有逗號,Sizzle 嘗試對此情況優化 if (match.length === 1) { tokens = match[0] = match[0].slice(0); // 第一個 TAG 為一個 ID 選擇器,設置快速查找 if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) { //將新 context 設置成那個 ID context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0]; if (!context) { // 第一個 ID 都找不到就直接返回 return results; // 此時 selector 為 function,應該有特殊用途 } else if (compiled) { context = context.parentNode; } selector = selector.slice(tokens.shift().value.length); } // 在沒有 CHILD 的情況,從右向左,仍然是對性能的優化 i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length; while (i--) { token = tokens[i]; // 碰到 +~ 等符號先停止 if (Expr.relative[(type = token.type)]) { break; } if ((find = Expr.find[type])) { // Search, expanding context for leading sibling combinators if ((seed = find( token.matches[0].replace(runescape, funescape), rsibling.test(tokens[0].type) && testContext(context.parentNode) || context))) { // testContext 是判斷 getElementsByTagName 是否存在 // If seed is empty or no tokens remain, we can return early tokens.splice(i, 1); selector = seed.length && toSelector(tokens); //selector 為空,表示到頭,直接返回 if (!selector) { push.apply(results, seed); return results; } break; } } } } // Compile and execute a filtering function if one is not provided // Provide `match` to avoid retokenization if we modified the selector above (compiled || compile(selector, match))( seed, context, !documentIsHTML, results, !context || rsibling.test(selector) && testContext(context.parentNode) || context); return results; } ``` toSelector 函數是將 tokens 除去已經選擇的將剩下的拼接成字符串: ``` function toSelector(tokens) { var i = 0, len = tokens.length, selector = ""; for (; i < len; i++) { selector += tokens[i].value; } return selector; } ``` 在最后又多出一個 compile 函數,是 Sizzle 的編譯函數,下章講。 到目前為止,該優化的都已經優化了,selector 和 context,還有 seed,而且如果執行到 compile 函數,這幾個變量的狀態: 1. selector 可能已經不上最初那個,經過各種去頭去尾; 2. match 沒變,仍是 tokensize 的結果; 3. seed 事種子集合,所有等待匹配 DOM 的集合; 4. context 可能已經是頭(#ID); 5. results 沒變。 可能,你也發現了,其實 compile 是一個異步函數 compile()()。 ## 總結 select 大概干了幾件事, 1. 將 tokenize 處理 selector 的結果賦給 match,所以 match 實為 tokens 數組; 2. 在長度為 1,且第一個 token 為 ID 的情況下,對 context 進行優化,把 ID 匹配到的元素賦給 context; 3. 若不含 needsContext 正則,則生成一個 seed 集合,為所有的最右 DOM 集合; 4. 最后事 compile 函數,參數真多...
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看