第十二课:Sizzle引擎详解
這篇博客難度太大,跟前端開發(fā)其實(shí)沒(méi)什么關(guān)系,如果你想成為大牛,那就去了解下吧。如果你還不想,那可以忽略,畢竟面試官也不會(huì)問(wèn)到這里來(lái),因?yàn)樗膊惶:呛恰?/p>
Sizzle引擎是jQuery的選擇器,它大部分操作都是從右到左進(jìn)行選擇,特殊選擇符會(huì)從左到右。用戶輸入$("div"),$("div p.class"),$("div [attr=val] :checked")等各種復(fù)雜的選擇符,它都能選擇到用戶想要取到的元素節(jié)點(diǎn)。
Sizzle的整體結(jié)構(gòu)如下:
(1)Sizzle主函數(shù),里面包含選擇符的切割,內(nèi)部循環(huán)調(diào)用主查找函數(shù),主過(guò)濾函數(shù),最后是去重過(guò)濾。
(2)其他輔助函數(shù),如 uniqueSort, matches ,matchesSelector。
(3)Sizzle.find主查找函數(shù)
(4)Sizzle.filter主過(guò)濾函數(shù)
(5)Sizzle.selectors 包含各種匹配用的正則,過(guò)濾用的正則,分解用的正則,預(yù)處理函數(shù),過(guò)濾函數(shù)。
(6)根據(jù)瀏覽器的特征設(shè)計(jì)makeArray,sortOrder,contains等方法。
(7)根據(jù)瀏覽器的特征重寫Sizzle.selectors中的部分查找函數(shù),過(guò)濾函數(shù),查找次序。
(8)若瀏覽器支持querySelectorAll,那么用它重寫Sizzle,將原來(lái)的Sizzle作為后備方案包裹在新的Sizzle里面。
(9)其他輔助函數(shù),如:isXML,posProcess。
Sizzle.find主查找函數(shù)和Sizzle.filter過(guò)濾函數(shù)實(shí)現(xiàn)原理:
對(duì)js原生的4大查找函數(shù),getElementById(針對(duì)id),getElementsByName(針對(duì)name),getElementsByTagName(針對(duì)標(biāo)簽名tagName,比如div,p),getElementsByClassName(針對(duì)class),進(jìn)行一層封裝,瀏覽器支持的話,就返回?cái)?shù)組或者NodeList,不支持的,就返回undefined。
這里需要講一下種子集,
種子集就是通過(guò)最右邊的選擇器組得到的元素集合。比如:"div.aaa span.bbb",最右邊的選擇器組就是"span.bbb",這時(shí)引擎會(huì)根據(jù)瀏覽器的支持情況選擇getElementsByTagName(span)或getElementsByClassName(bbb)得到一組元素,然后再通過(guò)class(bbb)或tagName(span)進(jìn)行過(guò)濾,這時(shí)得到的集合就是種子集。種子集是分兩步篩選出來(lái)的,首先,通過(guò)Sizzle.find得到一個(gè)大體的結(jié)果,然后通過(guò)Sizzle.filter過(guò)濾。那我們是先取span,還是.bbb呢?這里有一個(gè)準(zhǔn)則,要確保我們后面的映射集(當(dāng)我們?nèi)〉梅N子集后,會(huì)將種子集復(fù)制一份,這就是映射集)最小。為了達(dá)到此目的,這里有一個(gè)優(yōu)化,原生選擇器的調(diào)用順序被放在一個(gè)Sizzle.selectors.order的數(shù)組中,對(duì)于低版本瀏覽器,其順序?yàn)閕d,name,tagName,對(duì)于支持getElementsByClassName的瀏覽器,順序?yàn)閕d,class,name,tagName。因?yàn)閕d只返回一個(gè)元素,class與樣式相關(guān),不是每個(gè)元素都有這個(gè)類名的,name屬性使用到的幾率比較少,而tagName排除的元素比較少。所以Sizzle.find就會(huì)根據(jù)Sizzle.selectors.order數(shù)組,依次調(diào)用正則,從最右的選擇器中切下需要的部分,找到粗糙的節(jié)點(diǎn)集合。(針對(duì)"span.bbb",id調(diào)用正則時(shí),找不到,然后class,調(diào)用正則,找到.bbb,因此就調(diào)用getElementsByClassName(bbb)得到一組數(shù)據(jù),最后通過(guò)Sizzle.filter過(guò)濾取到的數(shù)據(jù),過(guò)濾條件是tagName(span))
映射集,
當(dāng)我們?nèi)〉梅N子集后,會(huì)將種子集復(fù)制一份,這就是映射集。種子集是由一個(gè)選擇器組選出來(lái)的,這時(shí)如果選擇符不為空(前面是"div.aaa"),必然往左就是關(guān)系選擇器(父親,兄弟,后代),關(guān)系選擇器會(huì)讓引擎去選取其兄長(zhǎng)或父親,把這些元素置換到映射集對(duì)等的位置上(個(gè)數(shù)不變,因此映射集和種子集的數(shù)量總是相當(dāng))。然后到下一個(gè)選擇器組時(shí)("div.aaa"),就是過(guò)濾操作了。主過(guò)濾函數(shù)Sizzle.filter會(huì)調(diào)用Sizzle.selectors下的N個(gè)過(guò)濾函數(shù)對(duì)這些元素進(jìn)行檢測(cè),將不符合的元素替換為false。因此到最后要去重排時(shí),映射集是一個(gè)包含布爾值與元素節(jié)點(diǎn)的數(shù)組。
下面就是根據(jù)瀏覽器的特征進(jìn)行優(yōu)化:
IE6,7下getElementById有bug。需要重寫。
IE6-IE8下,Array.prototype.slice.call無(wú)法切割NodeList。需要重寫makeArray。jQuery中直接用循環(huán),把類數(shù)組轉(zhuǎn)化成數(shù)組。
IE6-IE8下,getElementsByTagName("*"),會(huì)混雜注釋節(jié)點(diǎn)。
這里大家可能會(huì)提出現(xiàn)在有些瀏覽器支持querySelectorAll方法,這是原生的,可以用來(lái)選擇元素。
在Sizzle中,當(dāng)瀏覽器支持querySelectorAll方法時(shí),會(huì)重寫Sizzle。但是在重寫時(shí),會(huì)根據(jù)不同情況提出各種提速方案:
(1)getElementById還是比querySelectorAll速度快,因?yàn)間etElementById只返回一個(gè)元素,而且內(nèi)部做了緩存,但是querySelectorAll會(huì)返回?fù)碛羞@個(gè)id值的多個(gè)元素,盡管頁(yè)面id一般是唯一的,但如果出現(xiàn)了多個(gè)同樣id的情況下,getElementById還是只返回一個(gè)元素,而querySelectorAll會(huì)返回多個(gè)。
(2)getElementsByTagName內(nèi)部也使用了緩存,而且返回的是NodeList對(duì)象,querySelectorAll返回的是一個(gè)StaticNodeList對(duì)象,前面是動(dòng)態(tài)的,后面是靜態(tài)的。區(qū)別在于:document.getElementsByTagName("div") ==?document.getElementsByTagName("div"),返回真,document.querySelectorAll("div") ==?document.querySelectorAll("div"),返回false.返回true的,意味著它們拿到的同是cache引用。返回false意味著每次返回都是不一樣的object。數(shù)據(jù)表明:創(chuàng)建一個(gè)動(dòng)態(tài)的NodeList對(duì)象比創(chuàng)建一個(gè)靜態(tài)的StaticNodeList對(duì)象快90%.
?
加油!
?
轉(zhuǎn)載于:https://www.cnblogs.com/chaojidan/p/4140199.html
總結(jié)
以上是生活随笔為你收集整理的第十二课:Sizzle引擎详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: H3C S5500核心交换机策略路由调度
- 下一篇: 远程连接linux(Ubuntu配置SS