第二章 jQuery技術解密 (三)
2.3 破解 jQuery 選擇器介面
jQuery 選擇器功能強大,但是用法簡單,它僅僅提供了一個介面:jQuery(),也可以簡寫為 $() 。用法如此簡單,但又具有如此強大的處理能力,使 jQuery 必然成為眾人追捧的物件。
在上一節中,我們重點分析了 jQuery 框架的雛形,而對於選擇器並沒有深入分析,僅僅提供了一個簡單的 DOM 元素選擇作為演示,目的是方便讀者理解該框架的架設思路和過程。本節將重點研究 jQuery 選擇器的設計思路、實現過程和工作原理。
2.3.1 簡單但很複雜的黑洞
前面說到,jQuery 提供了惟一的介面 (jQuery() 或者 $()) 使選擇器與外界進行交流。那麼這個物件是如何生成的呢?
jQuery 框架的基礎是查詢,即查詢文件元素物件,因此我們可以認為 jQuery 物件就是一個選擇器,並在此基礎上構建和執行查詢過濾器。
jQuery 查詢的結果是獲取 DOM 元素,這些查詢到的 DOM 元素又是如何儲存的呢?
根據前面的介紹,我們初步瞭解到它把查詢的結果儲存到 jQuery 物件內。由於查詢的結果可能是單個元素,也可能是集合,因此,jQuery 物件內應該定義了一個集合。這個集合專門負責存放查詢到的 DOM 元素。這正如 JavaScript 中的 Function 物件一樣,其內部也構建了一個集合物件 Arguments ,專門負責儲存函式的引數。
但是,Functiono 物件和 Arguments 是兩個相互獨立的概念,僅通過 arguments 屬性聯絡在一起。也就是說 Arguments 物件並非是 Function 物件的子物件,或者是它的內部組成部分。而 jQuery 物件與查詢結果的資料集合就不同了,它是完全作為 jQuery 物件的一部分而存在的。
另外,jQuery 雖然僅提供了一個入口,但是它的構建並不只侷限於從 DOM 文件樹中查詢到 DOM 元素,DOM 元素也有可能從別的集合中轉移過來的,或者是從 HTML 片斷生成的等。
例如,類似下面的程式碼在 jQuery 應用中經常會看到。
$("div.red").css("display", "none"); // 將 class 為 red 的 div 元素隱藏顯示
var width = $("div .red").width(); // 獲取 div 元素下 class 為 red 的元素的寬度
var html = $(document.getElementById("wrap")).html(); // 獲取 id 為 wrap 元素的 innerHTML 值
$("#wrap", document.forms[0]).css("color", "red"); // 將在第一個 form 元素下 id 為 wrap 元素的字型顏色設定為紅色
$("<div>hello,world</div>").appendTo("#wrap"); // 將 HTML 字串資訊追加到 id 為 wrap 元素的末尾
在 $() 函式中可以包含選擇字串、HTML 字串、 DOM 物件和資料集合等不同型別的引數。jQuery 是如何分辨這些引數是選擇符字串、HTML字串、DOM物件或資料集合的呢?
為了方便讀者理解這其中的奧妙,我們不妨把 jQuery 框架進行簡化,先刪除所有方法、函式以及邏輯程式碼,然後在 init() 構造器中,使用 alert() 方法獲取 selector 引數的型別和資訊,其程式碼如下。
- <scripttype="text/javascript">
- (function(){
- varwindow=this;
- jQuery=window.jQuery=window.$=function(selector,context){
- returnnewjQuery.fn.init(selector,context);
- };
- jQuery.fn=jQuery.prototype={
- init:function(selector,context){
- alert(selector);
- }
- };
- })();
- window.onload=function(){
- $("div.red");//獲取"div.red"
- $("div.red");//獲取"div.red"
- $(document.getElementById("wrap"));//獲取"[object]"
- $("#wrap",document.forms[0]);//獲取"#wrap"
- $("<div>hello,world</div>");//獲取"<div>hello,world</div>"
- };
- </script>
- <divid="wrap"></div>
2.3.2 盤根錯節的邏輯關係
根據 jQuery 官網提供的 API 文件可知, jQuery() 提供了以下 4 種構建 jQuery 物件的方式。
- jQuery(expression, [context])
- jQuery(html, [ownerDocument])
- jQuery(elements)
- jQuery(callback)
2.3.3 jQuery 構造器
- 如果是單個 DOM 元素,可以直接把 DOM 元素作為陣列元素傳遞給 this 物件,還可以通過 ID 從 DOM 文件中查詢元素。
- 如果是多個 DOM 元素,則以集合形式附加,如 jQuery 物件、陣列和物件等,此時可以通過 CSS 選擇器匹配到所有 DOM 元素,然後過濾,最後構建類陣列的資料結構。
- <scripttype="text/javascript">
- (function(){
- var
- window=this,
- jQuery=window.jQuery=window.$=function(selector,context){
- returnnewjQuery.fn.init(selector,context);
- },
- quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/;
- //jQuery原型物件
- //構造jQuery物件的入口
- //所有jQuery物件方法都通過jQuery原型物件來繼承
- jQuery.fn=jQuery.prototype={
- //jQuery物件初始化構造器,相當於jQuery物件的型別,由該函式負責建立jQuery物件
- //引數說明:selector:選擇器的符號,可以是任意資料型別。考慮DOM元素操作需要,該引數應該是包含DOM元素的任何資料
- //context:上下文,指定在文件DOM中哪個節點下開始進行查詢,預設值為document
- init:function(selector,context){
- selector=selector||document;//確保selector引數存在,預設值為document
- //第一種情況,處理選擇符為DOM元素,此時將忽略上下文,即忽略第二個引數
- //例如,$(document.getElementById("wrap")),jQuery(DOMElement)匹配DOM元素。
- //先使用selector.nodeType判斷當selector為元素節點,將length設定為1,
- //並且賦值給context,實際上context作為init的第二個引數,
- //也意味著它的上下文節點就是selector該點,返回它的$(DOMElement)物件
- if(selector.nodeType){//存在nodeType屬性,說明選擇符是一個DOM元素
- this[0]=selector;//直接把當前引數的DOM元素存入類陣列中
- this.length=1;//設定類陣列的長度,以方便遍歷訪問
- this.context=selector;//設定上下文屬性
- returnthis;//返回jQuery物件,即類陣列物件
- }
- //如果選擇符引數為字串,則進行處理
- //例如,$("<div>hello,world</div>"),jQuery(html,[ownerDocument])匹配HTML字串
- if(typeofselector=="string"){
- //使用quickExpr正規表示式匹配該選擇符字串,決定是處理HTML字串,還是處理ID字串
- //quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/
- //quickExpr匹配包含<>的字串或#後跟[a-zA-Z0-9_]或-的字串
- varmatch=quickExpr.exec(selector);
- //驗證匹配的資訊,任何情況下都不是#id
- if(match&&(match[1]||!context)){
- //第二種情況,處理HTML字串,類似$(html)->$(array)
- if(match[1]){
- //selector=jQuery.clean([match[1]],context);
- }
- //第三種情況,處理ID字串,類似$("#id")
- else{
- varelem=document.getElementById(match[3]);//獲取該元素確保元素存在
- //處理在IE和Opera瀏覽器下根據name,而不是ID返回元素
- if(elem&&elem.id!=match[3]){
- //returnjQuery().find(selector);//預設呼叫document.find()方法
- }
- //否則將把elem作為元素引數直接呼叫jQuery()函式,返回jQuery物件
- varret=jQuery(elem||[]);
- ret.context=document;//設定jQuery物件的上下文屬性
- ret.selector=selector;//設定jQuery物件的選擇符屬性
- returnret;
- }
- }else{
- //第四種情況,處理jQuery(expression,[context])
- //例如,$("div.red")的表示式字串
- //returnjQuery(context).find(selector);
- }
- }//elseif(jQuery.isFunction(selector))
- //第五種情況,處理jQuery(callback),即$(document).ready()的簡寫
- //例如,$(function(){alert("hello,world");}),
- //或者$(document).ready(function(){alert("hello,world");});
- //returnjQuery(document).ready(selector);
- //確保舊的選擇符能夠通過
- if(selector.selector&&selector.context){
- this.selector=selector.selector;
- this.context=selector.context;
- }
- //第六種情況,處理類似$(elements)
- //returnthis.setArray(jQuery.isArray(selector)?selector:jQuery.makeArray(selector));
- }
- };
- })();
- </script>
- 情況一,第一個引數是 HTML 標籤字串,第二個引數可選,則執行 selector = jQuery.clean([match[1]], context); 該語句能夠把 HTML 字串轉換成 DOM 物件的陣列,然後執行 Array 型別陣列並返回 jQuery 物件。
- 情況二,第一個引數是 #id 字串,即類似 $(id),則先使用 document.getElementById() 方法獲取該元素,如果沒有獲得元素,則設定 selector = [],轉到執行 Array 型別,並返回空集合的 jQuery 物件。如果獲得元素,則構建 jQuery 物件並返回。這裡把 #id 單獨列出,是為了提高效能。
- 情況三,處理複雜的 CSS 選擇符字串,第二個引數是可選的。通過 return jQuery().find(selector); 語句實現。該語句先執行 jQuery(context) ,可以看出第二個引數 context 可以是任意值,也可以是集合資料。然後呼叫 find(selector) 找到 jQuery(context) 上下文中所有的 DOM 元素,即這些元素都滿足 selector 表示式,最後構建 jQuery 物件並返回。
相關文章
- 第二章 jQuery技術解密(一)jQuery解密
- 第二章 jQuery技術解密 (二)jQuery解密
- 第二章 jQuery技術解密 (四)jQuery解密
- 第二章 jQuery技術解密 (五)jQuery解密
- 第二章 jQuery技術解密 (六)jQuery解密
- 第二章 jQuery技術解密 (七)jQuery解密
- 第二章投資技術《第三節 K線秘籍》
- 讀《圖解密碼技術》(三):金鑰、隨機數和應用技術圖解解密密碼隨機
- 騰訊萬億級 Elasticsearch 技術解密Elasticsearch解密
- ChatGPT軟體技術棧解密ChatGPT解密
- Oracle Flashback 技術大解密Oracle解密
- 《Web前端黑客技術解密》讀書筆記(第三、四、五章)Web前端黑客解密筆記
- 精通struts技術第二章(4) (轉)
- 精通struts技術第二章(5) (轉)
- 解密數倉的SQL ON ANYWHERE技術解密SQL
- C#語言和資料庫技術基礎 ----------------- 第二章 簡答三 、C#資料庫
- 社交軟體紅包技術解密(十二):解密抖音春節紅包背後的技術設計與實踐解密
- 有獎書評活動:《京東技術解密》解密
- 第二章投資技術《第五節 背離》
- 讀《JavaScript核心技術開發解密》筆記JavaScript解密筆記
- 解密阿里巴巴安全技術體系解密阿里
- 【技術解密】SequoiaDB分散式儲存原理解密分散式
- [解密] DNA儲存技術究竟牛在哪裡?解密
- [原創]京東技術解密讀書筆記解密筆記
- jQuery第二章知識點jQuery
- jQuery第二章選擇器jQuery
- 華為網路技術-三層交換技術
- vivo營銷自動化技術解密|開篇解密
- 解密|一文帶你看懂外掛技術解密
- jQuery第二章課後作業jQuery
- 地球上最大的PHP站點後端技術解密PHP後端解密
- 解密阿里巴巴的技術發展路徑解密阿里
- 防禦網路威脅UTM技術解密(圖示)解密
- 三更技術社群
- 三層交換技術解析
- “聲討”高雲的《jQuery技術內幕》jQuery
- 個人練習前端技術使用Bootstrap、JQuery、thymeleaf前端bootjQuery
- Python技術分享:教你如何解密隔壁WiFi密碼Python解密WiFi密碼