溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

jQuery 2.0.3如何用源碼分析Sizzle引擎

發(fā)布時(shí)間:2021-11-09 17:42:02 來源:億速云 閱讀:117 作者:柒染 欄目:web開發(fā)

本篇文章給大家分享的是有關(guān)jQuery 2.0.3如何用源碼分析Sizzle引擎,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

什么是JavaScript的“預(yù)編譯”?

function Aaron() {     alert("hello"); }; Aaron(); //這里調(diào)用Aaron,輸出world而不是hello  function Aaron() {     alert("world"); }; Aaron(); //這里調(diào)用Aaron,當(dāng)然輸出world

按理說,兩個(gè)簽名完全相同的函數(shù),在其他編程語言中應(yīng)該是非法的。但在JavaScript中,這沒錯(cuò)。不過,程序運(yùn)行之后卻發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象:兩次調(diào)用都只是***那個(gè)函數(shù)里輸出的值!顯然***個(gè)函數(shù)沒有起到任何作用。這又是為什么呢?

JavaScript執(zhí)行引擎并非一行一行地分析和執(zhí)行程序,而是一段一段地進(jìn)行預(yù)編譯后讓后 再執(zhí)行的。而且,在同一段程序中,函數(shù) 在被執(zhí)行之前 會(huì)被預(yù)定義,后定定義的 同名函數(shù) 會(huì)覆蓋 先定義的函數(shù)。在調(diào)用函數(shù)的時(shí)候,只會(huì)調(diào)用后一個(gè)預(yù)定義的函數(shù)(因?yàn)楹笠粋€(gè)預(yù)定義的函數(shù)把前一個(gè)預(yù)定義的函數(shù)覆蓋了)。也就是說,在***次調(diào)用myfunc之前,***個(gè)函數(shù)語句定義的代碼邏輯,已被第二個(gè)函數(shù)定義語句覆蓋了。所以,兩次都調(diào)用都是執(zhí)行***一個(gè)函數(shù)邏輯了。

我們用實(shí)際證明下:

//***段代碼 <script>     function Aaron() {         alert("hello");     };     Aaron(); //hello </script>  //第二段代碼 <script>     function Aaron() {         alert("world");     };     Aaron(); //world </script>

一段代碼中的定義式函數(shù)語句會(huì)優(yōu)先執(zhí)行,這似乎有點(diǎn)象靜態(tài)語言的編譯概念。所以,這一特征也被有些人稱為:JavaScript的“預(yù)編譯”

所以總結(jié)下:JS 解析器在執(zhí)行語句前會(huì)將函數(shù)聲明和變量定義進(jìn)行"預(yù)編譯",而這個(gè)"預(yù)編譯",并非一個(gè)頁面一個(gè)頁面地"預(yù)編譯",而是一段一段地預(yù)編譯,所謂的段就是一 個(gè) <script> 塊。

那么我們再來看看

什么是編譯函數(shù)?

這個(gè)概念呢,我只用自己的語言表述下吧,先看看我在實(shí)際項(xiàng)目中的一種使用吧~

這里大概介紹下,偶做的是phonegap項(xiàng)目,基本實(shí)現(xiàn)了一套ppt的模板動(dòng)畫

PPT的的功能設(shè)置(支持生成3個(gè)平臺的應(yīng)用)

jQuery 2.0.3如何用源碼分析Sizzle引擎 jQuery 2.0.3如何用源碼分析Sizzle引擎

通過這個(gè)PPT直接描述出用戶行為的數(shù)據(jù),然后直接打包生成相對應(yīng)的實(shí)現(xiàn)應(yīng)用了,實(shí)現(xiàn)部分是JS+CSS3+html5 ,關(guān)鍵是可以跨平臺哦

PC上的效果

頁面的元素都是動(dòng)態(tài)的可運(yùn)行可以交互的

jQuery 2.0.3如何用源碼分析Sizzle引擎

移動(dòng)端的效果

jQuery 2.0.3如何用源碼分析Sizzle引擎

編譯出來的的APK

jQuery 2.0.3如何用源碼分析Sizzle引擎

通過一套PPT軟件生成的,頁面有大量的動(dòng)畫,聲音,視頻,路徑動(dòng)畫,交互,拖動(dòng) 等等效果,這里不細(xì)說了,那么我引入編譯函數(shù)這個(gè)概念我是用來干什么事呢?

一套大的體系,流程控制是非常重要的,簡單的來說呢就是在某個(gè)階段該干哪一件事件了

但是JS呢其實(shí)就是一套異步編程的模型

編寫異步代碼是時(shí)常的事,比如有常見的異步操作:

Ajax(XMLHttpRequest)

Image Tag,Script Tag,iframe(原理類似)

setTimeout/setInterval

CSS3 Transition/Animation

HTML5 Web Database

postMessage

Web Workers

Web Sockets

and more&hellip;

JavaScript是一門單線程語言,因此一旦有某個(gè)API阻塞了當(dāng)前線程,就相當(dāng)于阻塞了整個(gè)程序,所以“異步”在JavaScript編程中占有很重要的地位。異步編程對程序執(zhí)行效果的好處這里就不多談了,但是異步編程對于開發(fā)者來說十分麻煩,它會(huì)將程序邏輯拆分地支離破碎,語義完全丟失。因此,許多程序員都在打造一些異步編程模型已經(jīng)相關(guān)的API來簡化異步編程工作,例如Promise模型

現(xiàn)在有的異步流程控制大多是基于CommonJS Promises規(guī)范,比如  jsdeferred,jQuery自己的deferred等等

從用戶角度來說呢,越是功能強(qiáng)大的庫,則往往意味著更多的API,以及更多的學(xué)習(xí)時(shí)間,這樣開發(fā)者才能根據(jù)自身需求選擇最合適的方法

從開發(fā)者角度,API的粒度問題,粒度越大的API往往功能越強(qiáng),可以通過少量的調(diào)用完成大量工作,但粒度大往往意味著難以復(fù)用。越細(xì)粒度的API靈活度往往越高,可以通過有限的API組合出足夠的靈活性,但組合是需要付出“表現(xiàn)力”作為成本的。JavaScript在表現(xiàn)力方面有一些硬傷。

好像這里有點(diǎn)偏題了,總的來說呢,各種異步編程模型都是種抽象,它們是為了實(shí)現(xiàn)一些常用的異步編程模式而設(shè)計(jì)出來的一套有針對性的API。但是,在實(shí)際使用過程中我們可能遇到千變?nèi)f化的問題,一旦遇到模型沒有“正面應(yīng)對”的場景,或是觸及這種模型的限制,開發(fā)人員往往就只能使用一些相對較為丑陋的方式來“回避問題”

那么在我們實(shí)際的開發(fā)中呢,我們用JS表達(dá)一段邏輯,由于在各種環(huán)境上存在著各種不同的異步情景,代碼執(zhí)行流程會(huì)在這里“暫?!?,等待該異步操作結(jié)束,然后再繼續(xù)執(zhí)行后續(xù)代碼

如果是這樣的情況

var a = 1;  setTimeout(function(){     a++; },1000)  alert(a)//1

這段代碼很簡單,但是結(jié)果確不是我們想要的,我們修改一下

var a = 1;  var b = function(callback) {     setTimeout(function() {        a++;         callback();     }, 1000) }  b(function(){     alert(a)  //2 })

任何一個(gè)普通的JavaScript程序員都能順利理解這段代碼的含義,這里的“回調(diào)”并不是“阻塞”,而會(huì)空出執(zhí)行線程,直至操作完成。而且,假如系統(tǒng)本身沒有提供阻塞的API,我們甚至沒有“阻塞”代碼的方法(當(dāng)然,本就不該阻塞)。

到底編譯函數(shù)這個(gè)概念是干嘛?

JavaScript是單線程的,代碼也是同步從上向下執(zhí)行的,執(zhí)行流程不會(huì)隨便地暫停,當(dāng)遇到異步的情況,從而改變了整個(gè)執(zhí)行流程的時(shí)候,我們需要對代碼進(jìn)行自動(dòng)改寫,也就是在程序的執(zhí)行過程中動(dòng)態(tài)生成并執(zhí)行新的代碼,這個(gè)過程我想稱之為編譯函數(shù)的一種運(yùn)用吧.

我個(gè)人理解嘛,這里只是一個(gè)概念而已,閉包的一種表現(xiàn)方式,就像MVVM的angular就搞出一堆的概念,什么HTML編譯器,指令,表達(dá)式,依賴注入等等,當(dāng)然是跟Javaer有關(guān)系&hellip;

這里回到我之前的項(xiàng)目上面,我個(gè)人引入這個(gè)編譯函數(shù),是為了解決在流程中某個(gè)環(huán)節(jié)中因?yàn)楫惒綄?dǎo)致的整個(gè)流程的執(zhí)行出錯(cuò),所以在JS異步之后,我會(huì)把整個(gè)同步代碼編譯成一個(gè)閉包函數(shù),因?yàn)檫@樣可以保留整個(gè)作用域的訪問,這樣等異步處理完畢之后,直接調(diào)用這個(gè)編譯函數(shù)進(jìn)行匹配即可,這樣在異步的階段,同步的代碼也同時(shí)被處理了

jQuery 2.0.3如何用源碼分析Sizzle引擎jQuery 2.0.3如何用源碼分析Sizzle引擎

其實(shí)說白了,就是一種閉包的使用,只是在不同的場景中換了一個(gè)優(yōu)雅的詞匯罷了, 那么在sizzle中,引入這個(gè)編譯函數(shù)是解決什么問題了?

sizzle編譯函數(shù)

文章開頭就提到了,sizzle引入這個(gè)實(shí)現(xiàn)主要的作用是分詞的篩選,提高逐個(gè)匹配的效率

這里接著上一章節(jié) 解析原理

我們在經(jīng)過詞法分析,簡單過濾,找到適合的種子集合之后

最終的選擇器抽出了input這個(gè)種子合集seed

重組的選擇器selector

div > p + div.aaron input[type="checkbox"]

還有詞法分析合集 group

Sizzle中的元匹配器

通過tokenize最終分類出來的group分別都有對應(yīng)的幾種type

jQuery 2.0.3如何用源碼分析Sizzle引擎

每一種type都會(huì)有對應(yīng)的處理方法

Expr.filter = {     ATTR   : function (name, operator, check) {     CHILD  : function (type, what, argument, first, last) {     CLASS  : function (className) {     ID     : function (id) {     PSEUDO : function (pseudo, argument) {     TAG    : function (nodeNameSelector) { }

可以把“元”理解為“原子”,也就是最小的那個(gè)匹配器。每條選擇器規(guī)則最小的幾個(gè)單元可以劃分為:ATTR | CHILD | CLASS | ID | PSEUDO | TAG
在Sizzle里邊有一些工廠方法用來生成對應(yīng)的這些元匹配器,它就是Expr.filter。
舉2個(gè)例子(ID類型的匹配器由Expr.filter["ID"]生成,應(yīng)該是判斷elem的id屬性跟目標(biāo)屬性是否一致),

拿出2個(gè)源碼

//ID元匹配器工廠 Expr.filter["ID"] =  function( id ) {   var attrId = id.replace( runescape, funescape );   //生成一個(gè)匹配器,   return function( elem ) {     var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");     //去除節(jié)點(diǎn)的id,判斷跟目標(biāo)是否一致     return node && node.value === attrId;   }; };
//屬性元匹配器工廠 //name :屬性名 //operator :操作符 //check : 要檢查的值 //例如選擇器 [type="checkbox"]中,name="type" operator="=" check="checkbox" "ATTR": function(name, operator, check) {     //返回一個(gè)元匹配器     return function(elem) {         //先取出節(jié)點(diǎn)對應(yīng)的屬性值         var result = Sizzle.attr(elem, name);           //看看屬性值有木有!         if (result == null) {             //如果操作符是不等號,返回真,因?yàn)楫?dāng)前屬性為空 是不等于任何值的             return operator === "!=";         }         //如果沒有操作符,那就直接通過規(guī)則了         if (!operator) {             return true;         }          result += "";          //如果是等號,判斷目標(biāo)值跟當(dāng)前屬性值相等是否為真         return operator === "=" ? result === check :            //如果是不等號,判斷目標(biāo)值跟當(dāng)前屬性值不相等是否為真             operator === "!=" ? result !== check :             //如果是起始相等,判斷目標(biāo)值是否在當(dāng)前屬性值的頭部             operator === "^=" ? check && result.indexOf(check) === 0 :             //這樣解釋: lang*=en 匹配這樣 <html lang="xxxxenxxx">的節(jié)點(diǎn)             operator === "*=" ? check && result.indexOf(check) > -1 :             //如果是末尾相等,判斷目標(biāo)值是否在當(dāng)前屬性值的末尾             operator === "$=" ? check && result.slice(-check.length) === check :             //這樣解釋: lang~=en 匹配這樣 <html lang="zh_CN en">的節(jié)點(diǎn)             operator === "~=" ? (" " + result + " ").indexOf(check) > -1 :             //這樣解釋: lang=|en 匹配這樣 <html lang="en-US">的節(jié)點(diǎn)             operator === "|=" ? result === check || result.slice(0, check.length + 1) === check + "-" :             //其他情況的操作符號表示不匹配             false;     }; },

到這里應(yīng)該想到Sizzle其實(shí)是不是就是通過對selector做“分詞”,打散之后再分別從Expr.filter 里面去找對應(yīng)的方法來執(zhí)行具體的查詢或者過濾的操作?

答案基本是肯定的

但是這樣常規(guī)的做法邏輯上是OK的,但是效率如何?

所以Sizzle有更具體和巧妙的做法

Sizzle在這里引入了 編譯函數(shù)的概念

通過Sizzle.compile方法內(nèi)部的,

matcherFromTokens  matcherFromGroupMatchers

把分析關(guān)系表,生成用于匹配單個(gè)選擇器群組的函數(shù)

matcherFromTokens,它充當(dāng)了selector“分詞”與Expr中定義的匹配方法的串聯(lián)與紐帶的作用,可以說選擇符的各種排列組合都是能適應(yīng)的了。Sizzle巧妙的就是它沒有直接將拿到的“分詞”結(jié)果與Expr中的方法逐個(gè)匹配逐個(gè)執(zhí)行,而是先根據(jù)規(guī)則組合出一個(gè)大的匹配方法,***一步執(zhí)行

我們看看如何用matcherFromTokens來生成對應(yīng)Token的匹配器?

先貼源碼

Sizzle.compile

//編譯函數(shù)機(jī)制         //通過傳遞進(jìn)來的selector和match生成匹配器:         compile = Sizzle.compile = function(selector, group /* Internal Use Only */ ) {             var i,                  setMatchers = [],                  elementMatchers = [],                  cached = compilerCache[selector + " "];              if (!cached) { //依舊看看有沒有緩存                  // Generate a function of recursive functions that can be used to check each element                 if (!group) {                     //如果沒有詞法解析過                     group = tokenize(selector);                 }                 i = group.length; //從后開始生成匹配器                 //如果是有并聯(lián)選擇器這里多次等循環(huán)                 while (i--) {                     //這里用matcherFromTokens來生成對應(yīng)Token的匹配器                     cached = matcherFromTokens(group[i]);                     if (cached[expando]) {                         setMatchers.push(cached);                     } else { //普通的那些匹配器都壓入了elementMatchers里邊                         elementMatchers.push(cached);                     }                 }                 // Cache the compiled function                 // 這里可以看到,是通過matcherFromGroupMatchers這個(gè)函數(shù)來生成最終的匹配器                 cached = compilerCache(selector, matcherFromGroupMatchers(elementMatchers, setMatchers));             }             //把這個(gè)***匹配器返回到select函數(shù)中             return cached;         };

matcherFromTokens

 1:      //生成用于匹配單個(gè)選擇器組的函數(shù)  2:      //充當(dāng)了selector“tokens”與Expr中定義的匹配方法的串聯(lián)與紐帶的作用,  3:      //可以說選擇符的各種排列組合都是能適應(yīng)的了  4:      //Sizzle巧妙的就是它沒有直接將拿到的“分詞”結(jié)果與Expr中的方法逐個(gè)匹配逐個(gè)執(zhí)行,  5:      //而是先根據(jù)規(guī)則組合出一個(gè)大的匹配方法,***一步執(zhí)行。但是組合之后怎么執(zhí)行的  6:      function matcherFromTokens(tokens) {  7:          var checkContext, matcher, j,  8:              len = tokens.length,  9:              leadingRelative = Expr.relative[tokens[0].type], 10:              implicitRelative = leadingRelative || Expr.relative[" "], //親密度關(guān)系 11:              i = leadingRelative ? 1 : 0, 12:    13:              // The foundational matcher ensures that elements are reachable from top-level context(s) 14:              // 確保這些元素可以在context中找到 15:              matchContext = addCombinator(function(elem) { 16:                  return elem === checkContext; 17:              }, implicitRelative, true), 18:              matchAnyContext = addCombinator(function(elem) { 19:                  return indexOf.call(checkContext, elem) > -1; 20:              }, implicitRelative, true), 21:    22:              //這里用來確定元素在哪個(gè)context 23:              matchers = [ 24:                  function(elem, context, xml) { 25:                      return (!leadingRelative && (xml || context !== outermostContext)) || ( 26:                          (checkContext = context).nodeType ? 27:                          matchContext(elem, context, xml) : 28:                          matchAnyContext(elem, context, xml)); 29:                  } 30:              ]; 31:    32:          for (; i < len; i++) { 33:              // Expr.relative 匹配關(guān)系選擇器類型 34:              // "空 > ~ +" 35:              if ((matcher = Expr.relative[tokens[i].type])) { 36:                  //當(dāng)遇到關(guān)系選擇器時(shí)elementMatcher函數(shù)將matchers數(shù)組中的函數(shù)生成一個(gè)函數(shù) 37:                  //(elementMatcher利用了閉包所以matchers一直存在內(nèi)存中) 38:                  matchers = [addCombinator(elementMatcher(matchers), matcher)]; 39:              } else { 40:                  //過濾  ATTR CHILD CLASS ID PSEUDO TAG 41:                  matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches); 42:    43:                  // Return special upon seeing a positional matcher 44:                  //返回一個(gè)特殊的位置匹配函數(shù) 45:                  //偽類會(huì)把selector分兩部分 46:                  if (matcher[expando]) { 47:                      // Find the next relative operator (if any) for proper handling 48:                      // 發(fā)現(xiàn)下一個(gè)關(guān)系操作符(如果有話)并做適當(dāng)處理 49:                      j = ++i; 50:                      for (; j < len; j++) { 51:                          if (Expr.relative[tokens[j].type]) { //如果位置偽類后面還有關(guān)系選擇器還需要篩選 52:                              break; 53:                          } 54:                      } 55:                      return setMatcher( 56:                          i > 1 && elementMatcher(matchers), 57:                          i > 1 && toSelector( 58:                              // If the preceding token was a descendant combinator, insert an implicit any-element `*` 59:                              tokens.slice(0, i - 1).concat({ 60:                                  value: tokens[i - 2].type === " " ? "*" : "" 61:                              }) 62:                          ).replace(rtrim, "$1"), 63:                          matcher, 64:                          i < j && matcherFromTokens(tokens.slice(i, j)), //如果位置偽類后面還有選擇器需要篩選 65:                          j < len && matcherFromTokens((tokenstokens = tokens.slice(j))), //如果位置偽類后面還有關(guān)系選擇器還需要篩選 66:                          j < len && toSelector(tokens) 67:                      ); 68:                  } 69:                  matchers.push(matcher); 70:              } 71:          } 72:    73:          return elementMatcher(matchers); 74:      }

重點(diǎn)就是

cached = matcherFromTokens(group[i]);

cached 的結(jié)果就是matcherFromTokens返回的matchers編譯函數(shù)了

matcherFromTokens的分解是有規(guī)律的:

語義節(jié)點(diǎn)+關(guān)系選擇器的組合

div > p + div.aaron input[type="checkbox"]

Expr.relative 匹配關(guān)系選擇器類型

當(dāng)遇到關(guān)系選擇器時(shí)elementMatcher函數(shù)將matchers數(shù)組中的函數(shù)生成一個(gè)函數(shù)

在遞歸分解tokens中的詞法元素時(shí)

提出***個(gè)typ匹配到對應(yīng)的處理方法

matcher = Expr.filter[tokens[i].type].apply(null, tokens[i].matches);  "TAG": function(nodeNameSelector) {                 var nodeName = nodeNameSelector.replace(runescape, funescape).toLowerCase();                 return nodeNameSelector === "*" ?                     function() {                         return true;                  } :                     function(elem) {            return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;                 };             },

matcher其實(shí)最終結(jié)果返回的就是bool值,但是這里返回只是一個(gè)閉包函數(shù),不會(huì)馬上執(zhí)行,這個(gè)過程換句話就是 編譯成一個(gè)匿名函數(shù)

繼續(xù)往下分解

如果遇到關(guān)系選著符就會(huì)合并分組了

matchers = [addCombinator(elementMatcher(matchers), matcher)];

通過elementMatcher生成一個(gè)***匹配器

function elementMatcher(matchers) {         //生成一個(gè)***匹配器         return matchers.length > 1 ?         //如果是多個(gè)匹配器的情況,那么就需要elem符合全部匹配器規(guī)則             function(elem, context, xml) {                 var i = matchers.length;                 //從右到左開始匹配                 while (i--) {                     //如果有一個(gè)沒匹配中,那就說明該節(jié)點(diǎn)elem不符合規(guī)則                     if (!matchers[i](elem, context, xml)) {                         return false;                     }                 }                 return true;         } :         //單個(gè)匹配器的話就返回自己即可             matchers[0];     }

看代碼大概就知道,就是分解這個(gè)子匹配器了,返回又一個(gè)curry函數(shù),給addCombinator方法

//addCombinator方法就是為了生成有位置詞素的匹配器。     function addCombinator(matcher, combinator, base) {         var dir = combinator.dir,             checkNonElements = base && dir === "parentNode",             donedoneName = done++; //第幾個(gè)關(guān)系選擇器          return combinator.first ?         // Check against closest ancestor/preceding element         // 檢查最靠近的祖先元素         // 如果是緊密關(guān)系的位置詞素         function(elem, context, xml) {             while ((elemelem = elem[dir])) {                 if (elem.nodeType === 1 || checkNonElements) {                     //找到***個(gè)親密的節(jié)點(diǎn),立馬就用***匹配器判斷這個(gè)節(jié)點(diǎn)是否符合前面的規(guī)則                     return matcher(elem, context, xml);                 }             }         } :          // Check against all ancestor/preceding elements         //檢查最靠近的祖先元素或兄弟元素(概據(jù)>、~、+還有空格檢查)         //如果是不緊密關(guān)系的位置詞素         function(elem, context, xml) {             var data, cache, outerCache,                 dirkey = dirruns + " " + doneName;              // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching             // 我們不可以在xml節(jié)點(diǎn)上設(shè)置任意數(shù)據(jù),所以它們不會(huì)從dir緩存中受益             if (xml) {                 while ((elemelem = elem[dir])) {                     if (elem.nodeType === 1 || checkNonElements) {                         if (matcher(elem, context, xml)) {                             return true;                         }                     }                 }             } else {                 while ((elemelem = elem[dir])) {                     //如果是不緊密的位置關(guān)系                     //那么一直匹配到true為止                     //例如祖宗關(guān)系的話,就一直找父親節(jié)點(diǎn)直到有一個(gè)祖先節(jié)點(diǎn)符合規(guī)則為止                     if (elem.nodeType === 1 || checkNonElements) {                         outerCache = elem[expando] || (elem[expando] = {});                         //如果有緩存且符合下列條件則不用再次調(diào)用matcher函數(shù)                         if ((cache = outerCache[dir]) && cache[0] === dirkey) {                             if ((data = cache[1]) === true || data === cachedruns) {                                 return data === true;                             }                         } else {                             cache = outerCache[dir] = [dirkey];                             cache[1] = matcher(elem, context, xml) || cachedruns; //cachedruns//正在匹配第幾個(gè)元素                             if (cache[1] === true) {                                 return true;                             }                         }                     }                 }             }         };     }

matcher為當(dāng)前詞素前的“匹配器”

combinator為位置詞素

根據(jù)關(guān)系選擇器檢查

如果是這類沒有位置詞素的選擇器:&rsquo;#id.aaron[name="checkbox"]&lsquo;

從右到左依次看看當(dāng)前節(jié)點(diǎn)elem是否匹配規(guī)則即可。但是由于有了位置詞素,

那么判斷的時(shí)候就不是簡單判斷當(dāng)前節(jié)點(diǎn)了,

可能需要判斷elem的兄弟或者父親節(jié)點(diǎn)是否依次符合規(guī)則。

這是一個(gè)遞歸深搜的過程。

所以matchers又經(jīng)過一層包裝了

然后用同樣的方式遞歸下去,直接到tokens分解完畢

返回的結(jié)果一個(gè)根據(jù)關(guān)系選擇器分組后在組合的嵌套很深的閉包函數(shù)了

看看結(jié)構(gòu)

jQuery 2.0.3如何用源碼分析Sizzle引擎

但是組合之后怎么執(zhí)行?

superMatcher方法是matcherFromGroupMatchers( elementMatchers, setMatchers )方法return出來的,但是執(zhí)行起重要作用的是它

以上就是jQuery 2.0.3如何用源碼分析Sizzle引擎,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI