jQuery 從 1.3 版本開始,使用了新的選擇器引擎 Sizzle(官方網址 http://sizzlejs.com) 。Sizzle 是 jQuery 作者 John Resig 開發的 DOM 選擇器引擎 (Dom Selector Engine),速度號稱業界第一。而且它有一個重要的特點就是 Sizzle 是完全獨立於 jQuery 的,如果用戶不想用 jQuery ,還可以只用 Sizzle 。
Sizzle 選擇器引擎目前成爲 jQuery 框架默認的選擇器引擎,相比原來的 jQuery 引擎,速度有很大的提升,如圖 2.3 所示的各種選擇器執行效率的對比。
2.4.1 回顧CSS的選擇器
在解析 jQuery 選擇器引擎 Sizzle 之前,我們不妨回顧一下 CSS 的選擇器 (CSS selector) 。CSS選擇器可以分爲三種基本類型:ID選擇器 (#id)、Class選擇器(.class)和類型(type)選擇器(p)。
另外,CSS還支持高級選擇器,如屬性選擇器 (attribute)、僞類或僞對象選擇器 (Pseudo Classes) 等。這些都是單一的選擇器,可以在應用中把它們組合起來,形成組合選擇器,如 div#id,div:last-child。組合型選擇器又包括多種關係形式,如包含關係、並列關係、相鄰關係和父子關係等。
2.4.2 解析 jQuery 選擇器引擎的設計思路
儘管 jQuery 選擇器引擎 Sizzle 非常複雜,功能也非常強大,但是它們都是建立在 JavaScript 已定義的方法或屬性基礎上來實現的。這主要包括元素的 getElementsByTagName() 和 getElementById() 方法,以及元素的 childNodes、firstChild、lastChild、nextSibling、parentNode 和 previousSibling 屬性。藉助這些方法和屬性可以直接或間接地選擇相匹配的 DOM 元素。
爲了方便講解,我們結合一個選擇器進行說明。選擇器代碼如下所示。
$("div.red");
這是一個複合選擇器,一搬讀者可以這樣分析:在DOM文檔樹中找到 class 屬性等於 "red" 的 div 元素。即一步到位,直接從DOM文檔樹中選擇所需要的元素。實際上,如果根據選擇器引擎的工作方式,可以把這個字符串拆分成兩步走。
- 第一步,根據 document.getElementsByTagName() 方法選擇文檔樹中的 div 元素集合。
- 第二步,根據其 class 是否等於 "red" 進行判斷,把不等於該值的元素從結果集中去掉。
- 第一步,根據 document.getElementsByTagName() 方法選擇文檔樹中的 div 元素集合。
- 第二步,迭代 div 元素集合,在所有的 div 元素中查找每個 div 元素下的 p 元素。
- 第三步,合併結果。
- 第一步,根據 document.getElementsByTagName() 方法選擇文檔樹中的 p 元素集合。
- 第二步,迭代 p 元素集合,在所有的 p 元素中查找每個 p 元素的父級元素。
- 第三步,檢測父級元素。如果不是 div 元素,則遍歷上一級元素;如果迭代到文檔樹的頂層,則排除該 p 元素;如果是 div 元素,則保存該 p 元素。
2.4.3 選擇器和過濾器
- 第一類,選擇器 (selector) 。即根據給定的選擇符,從 DOM 文檔樹找到相關的元素節點,並存儲到結果集中。
- 第二類,過濾器 (filter) 。根據表達式的條件,在結果集中過濾元素。
- 如果它們在 selector 字符串的起始位置,那麼它們也可以完成選擇功能。例如 ("#id");、 (".class");。
- 如果它們不在起始位置,那麼就應該作爲篩選器實現。例如 ("div#id"); 、 ("div.class"); 。
2.4.4 Sizzle 引擎結構
- <script type="text/javascript">
- /*!
- * Sizzle CSS Selector Engine - v0.9.3
- * Copyright 2009, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- * More information: http://sizzlejs.com/
- */
- // 把 Sizzle 引擎封裝在一個獨立的空間中
- (function(){
- // 定義用於塊識別器的正則表達式
-
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|]*\]|[‘"][^’"]*[‘"]|[^[\]’"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
(?:\[[[ - done = 0,
- toString = Object.prototype.toString;
- // Sizzle 選擇器引擎構造器函數
- // 參數說明:
- // selector: 選擇器字符串
- // context: 上下文
- // results: 結果集
- // seed: 種子
- var Sizzle = function(selector, context, results, seed) {
- // 省略的函數體
- };
- // Sizzle 匹配函數
- // 參數說明:
- // expr: 匹配表達式
- // set: 條件設置選項
- Sizzle.matches = function(expr, set){
- return Sizzle(expr, null, null, set);
- };
- // Sizzle 查詢函數
- // 參數說明:
- // expr: 查詢表達式
- // context: 上下文
- // isXML: 檢測函數
- Sizzle.find = function(expr, context, isXML){
- // 省略的函數體
- };
- // Sizzle 過濾函數
- // 參數說明:
- // expr: 過濾表達式
- // set: 條件設置選項
- // inplace: 包含項
- // not: 排除項
- Sizzle.filter = function(expr, set, inplace, not){
- // 省略的函數體
- };
- // Sizzle 表達式對象
- // 列舉所用的各種匹配表達式
- var Expr = Sizzle.selectors = {
- // 省略成員屬性
- };
- // 省略其他輔助性工具函數和邏輯代碼暴露的接口
- jQuery.find = Sizzle;
- jQuery.filter = Sizzle.filter;
- jQuery.expr = Sizzle.selectors;
- jQuery.expr[":"] = jQuery.expr.filters;
- // 定義的公共函數
- Sizzle.selectors.filters.hidden = function(elem){};
- Sizzle.selectors.filters.visible = function(elem){};
- Sizzle.selectors.filters.animated = function(elem){};
- jQuery.multiFilter = function(expr, elems, not){};
- jQuery.dir = function(elem, dir){};
- jQuery.nth = function(cur, result, dir, elem){};
- jQuery.sibling = function(n, elem){};
- return;
- window.Sizzle = Sizzle;
- })();
- </script>
通過上面的結構分析,可以看到 Sizzle 引擎主要包括一個構造器 Sizzle(),三個核心功能函數 matches()、find() 和 filter() ,以及一個表達式對象 selectors 。下面分別對它們進行講解。