国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

jQuery 源碼系列(五)sizzle 后續(xù)

newtrek / 1042人閱讀

摘要:歡迎來我的專欄查看系列文章。現(xiàn)在我們?cè)賮砝硪焕頂?shù)組,這個(gè)數(shù)組目前是一個(gè)多重?cái)?shù)組,現(xiàn)在不考慮逗號(hào)的情況,暫定只有一個(gè)分支。源碼源碼之前,來看幾個(gè)正則表達(dá)式。

歡迎來我的專欄查看系列文章。

select 函數(shù)

前面已經(jīng)介紹了 tokensize 函數(shù)的功能,已經(jīng)生成了一個(gè) tokens 數(shù)組,而且對(duì)它的組成我們也做了介紹,下面就是介紹對(duì)這個(gè) tokens 數(shù)組如何處理。

DOM 元素之間的連接關(guān)系大概有 > + ~ 幾種,包括空格,而 tokens 數(shù)組中是 type 是有 tag、attr 和連接符之分的,區(qū)分它們 Sizzle 也是有一套規(guī)則的,比如上一章我們所講的 Expr 對(duì)象,它真的非常重要:

Expr.relative = {
  ">": { dir: "parentNode", first: true },
  " ": { dir: "parentNode" },
  "+": { dir: "previousSibling", first: true },
  "~": { dir: "previousSibling" }
};

Expr.relative 標(biāo)記用來將連接符區(qū)分,對(duì)其種類又根據(jù)目錄進(jìn)行劃分。

現(xiàn)在我們?cè)賮砝硪焕?tokens 數(shù)組,這個(gè)數(shù)組目前是一個(gè)多重?cái)?shù)組,現(xiàn)在不考慮逗號(hào)的情況,暫定只有一個(gè)分支。如果我們使用從右向左的匹配方式的話,div > div.seq h2 ~ p,會(huì)先得到 type 為 TAG 的 token,而對(duì)于 type 為 ~ 的 token 我們已經(jīng)可以用 relative 對(duì)象來判斷,現(xiàn)在來介紹 Expr.find 對(duì)象:

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(){...};

實(shí)際上 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 [];
    }
  };
}

可以對(duì) find 對(duì)象進(jìn)行簡化:

Expr.find = {
  "ID": document.getElementById,
  "CLASS": document.getElementsByClassName,
  "TAG": document.getElementsByTagName
}

以后還會(huì)介紹 Expr.filter

select 源碼

源碼之前,來看幾個(gè)正則表達(dá)式。

var runescape = /([da-f]{1,6}[x20	
f]?|([x20	
f])|.)/gi
//這個(gè)正則是用來對(duì)轉(zhuǎn)義字符特殊處理,帶個(gè)反斜杠的 token
runescape.exec("ab"); //["ab", "ab", undefined]
var rsibling = /[+~]/; //匹配 +、~

matchExpr["needsContext"] = /^[x20	
f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:([x20	
f]*((?:-d)?d*)[x20	
f]*)|)(?=[^-]|$)/i
//needsContext 用來匹配不完整的 selector
matchExpr["needsContext"].test(" + p")//true
matchExpr["needsContext"].test(":first-child p")//true
//這個(gè)不完整,可能是由于抽調(diào) #ID 導(dǎo)致的

而對(duì)于 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);
}

我完全看不懂啦,你們自己意會(huì)去吧,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,即表示沒有逗號(hào),Sizzle 嘗試對(duì)此情況優(yōu)化
  if (match.length === 1) {
    tokens = match[0] = match[0].slice(0);
    // 第一個(gè) TAG 為一個(gè) ID 選擇器,設(shè)置快速查找
    if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && Expr.relative[tokens[1].type]) {
      //將新 context 設(shè)置成那個(gè) ID
      context = (Expr.find["ID"](token.matches[0].replace(runescape, funescape), context) || [])[0];
      if (!context) {
        // 第一個(gè) ID 都找不到就直接返回
        return results;

      // 此時(shí) selector 為 function,應(yīng)該有特殊用途
      } else if (compiled) {
        context = context.parentNode;
      }

      selector = selector.slice(tokens.shift().value.length);
    }

    // 在沒有 CHILD 的情況,從右向左,仍然是對(duì)性能的優(yōu)化
    i = matchExpr["needsContext"].test(selector) ? 0 : tokens.length;
    while (i--) {
      token = tokens[i];

      // 碰到 +~ 等符號(hào)先停止
      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 函數(shù)是將 tokens 除去已經(jīng)選擇的將剩下的拼接成字符串:

function toSelector(tokens) {
  var i = 0,
    len = tokens.length,
    selector = "";
  for (; i < len; i++) {
    selector += tokens[i].value;
  }
  return selector;
}

在最后又多出一個(gè) compile 函數(shù),是 Sizzle 的編譯函數(shù),下章講。

到目前為止,該優(yōu)化的都已經(jīng)優(yōu)化了,selector 和 context,還有 seed,而且如果執(zhí)行到 compile 函數(shù),這幾個(gè)變量的狀態(tài):

selector 可能已經(jīng)不上最初那個(gè),經(jīng)過各種去頭去尾;

match 沒變,仍是 tokensize 的結(jié)果;

seed 事種子集合,所有等待匹配 DOM 的集合;

context 可能已經(jīng)是頭(#ID);

results 沒變。

可能,你也發(fā)現(xiàn)了,其實(shí) compile 是一個(gè)異步函數(shù) compile()()

總結(jié)

select 大概干了幾件事,

將 tokenize 處理 selector 的結(jié)果賦給 match,所以 match 實(shí)為 tokens 數(shù)組;

在長度為 1,且第一個(gè) token 為 ID 的情況下,對(duì) context 進(jìn)行優(yōu)化,把 ID 匹配到的元素賦給 context;

若不含 needsContext 正則,則生成一個(gè) seed 集合,為所有的最右 DOM 集合;

最后事 compile 函數(shù),參數(shù)真多...

參考

jQuery 2.0.3 源碼分析Sizzle引擎 - 解析原理

本文在 github 上的源碼地址,歡迎來 star。

歡迎來我的博客交流。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/88135.html

相關(guān)文章

  • jQuery 源碼系列(四)Tokens 詞法分析

    摘要:歡迎來我的專欄查看系列文章。我們以為例,這是一個(gè)很簡單的,逗號(hào)將表達(dá)式分成兩部分。這是針對(duì)于存在的情況,對(duì)于不存在的情況,其就是的操作,后面會(huì)談到。參考源碼分析引擎詞法解析選擇器參考手冊(cè)本文在上的源碼地址,歡迎來。 歡迎來我的專欄查看系列文章。 在編譯原理中,詞法分析是一個(gè)非常關(guān)鍵的環(huán)節(jié),詞法分析器讀入字節(jié)流,然后根據(jù)關(guān)鍵字、標(biāo)識(shí)符、標(biāo)點(diǎn)、字符串等進(jìn)行劃分,生成單詞。Sizzle 選擇...

    rollback 評(píng)論0 收藏0
  • jQuery 源碼系列(三)sizzle 選擇器

    摘要:原本是中用來當(dāng)作選擇器的,后來被單獨(dú)分離出去,成為一個(gè)單獨(dú)的項(xiàng)目,可以直接導(dǎo)入到項(xiàng)目中使用。。本來我們使用當(dāng)作選擇器,選定一些或,使用或就可以很快鎖定所在的位置,然后返回給當(dāng)作對(duì)象。的優(yōu)勢使用的是從右向左的選擇方式,這種方式效率更高。 歡迎來我的專欄查看系列文章。 Sizzle 原本是 jQuery 中用來當(dāng)作 DOM 選擇器的,后來被 John Resig 單獨(dú)分離出去,成為一個(gè)單獨(dú)...

    icyfire 評(píng)論0 收藏0
  • jQuery 源碼系列(六)sizzle 編譯

    摘要:一種比較合理的方法就是對(duì)應(yīng)每個(gè)可判斷的生成一個(gè)閉包函數(shù),統(tǒng)一進(jìn)行查找。根據(jù)關(guān)系編譯閉包函數(shù),為四組編譯函數(shù)主要借助和。第四步將所有的編譯閉包函數(shù)放到一起,生成函數(shù)。 歡迎來我的專欄查看系列文章。 compile 講了這么久的 Sizzle,總感覺差了那么一口氣,對(duì)于一個(gè) selector,我們把它生成 tokens,進(jìn)行優(yōu)化,優(yōu)化的步驟包括去頭和生成 seed 集合。對(duì)于這些種子集合,...

    Terry_Tai 評(píng)論0 收藏0
  • jQuery 源碼系列(二)init 介紹

    摘要:源碼中接受個(gè)參數(shù),空參數(shù),這個(gè)會(huì)直接返回一個(gè)空的對(duì)象,。,這是一個(gè)標(biāo)準(zhǔn)且常用法,表示一個(gè)選擇器,這個(gè)選擇器通常是一個(gè)字符串,或者等,表示選擇范圍,即限定作用,可為,對(duì)象。,會(huì)把普通的對(duì)象或?qū)ο蟀b在對(duì)象中。介紹完入口,就開始來看源碼。 歡迎來我的專欄查看系列文章。 init 構(gòu)造器 前面一講總體架構(gòu)已經(jīng)介紹了 jQuery 的基本情況,這一章主要來介紹 jQuery 的入口函數(shù) jQu...

    Tony_Zby 評(píng)論0 收藏0
  • jQuery 源碼系列(七)Callbacks 函數(shù)

    摘要:的支持的方法有幾個(gè)主要的,和,比如官方有一個(gè)例子這兩個(gè)作為函數(shù)調(diào)用的生成從基本可以看出,函數(shù)生成了一個(gè)對(duì)象,這個(gè)對(duì)象的方法是添加回調(diào)函數(shù),而方法則是執(zhí)行回調(diào)函數(shù)。 歡迎來我的專欄查看系列文章。 講真,Sizzle 的源碼真的太壓抑了,以至于寫 Sizzle 文章的這段時(shí)間里都非常的痛苦,剛開始覺得它還挺有意思的,越到后面越覺得代碼很難讀懂,煩。 寒假也過完了,在家里待了兩周的時(shí)間,感覺...

    timger 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<