日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
【深入淺出jQuery】源碼淺析--整體架構(gòu)

最近一直在研讀 jQuery 源碼,初看源碼一頭霧水毫無頭緒,真正靜下心來細看寫的真是精妙,讓你感嘆代碼之美。

成都創(chuàng)新互聯(lián)公司是一家以網(wǎng)絡(luò)技術(shù)公司,為中小企業(yè)提供網(wǎng)站維護、成都做網(wǎng)站、網(wǎng)站制作、網(wǎng)站備案、服務(wù)器租用、空間域名、軟件開發(fā)、小程序開發(fā)等企業(yè)互聯(lián)網(wǎng)相關(guān)業(yè)務(wù),是一家有著豐富的互聯(lián)網(wǎng)運營推廣經(jīng)驗的科技公司,有著多年的網(wǎng)站建站經(jīng)驗,致力于幫助中小企業(yè)在互聯(lián)網(wǎng)讓打出自已的品牌和口碑,讓企業(yè)在互聯(lián)網(wǎng)上打開一個面向全國乃至全球的業(yè)務(wù)窗口:建站歡迎聯(lián)系:18982081108

其結(jié)構(gòu)明晰,高內(nèi)聚、低耦合,兼具優(yōu)秀的性能與便利的擴展性,在瀏覽器的兼容性(功能缺陷、漸進增強)優(yōu)雅的處理能力以及 Ajax 等方面周到而強大的定制功能無不令人驚嘆。

另外,閱讀源碼讓我接觸到了大量底層的知識。對原生JS 、框架設(shè)計、代碼優(yōu)化有了全新的認識,接下來將會寫一系列關(guān)于 jQuery 解析的文章。

網(wǎng)上已經(jīng)有很多解讀 jQuery 源碼的文章了,作為系列開篇的第一篇,思前想去起了個【深入淺出jQuery】的標(biāo)題,資歷尚淺,無法對 jQuery 分析的頭頭是道,但是 jQuery 源碼當(dāng)中確實有著大量巧妙的設(shè)計,不同層次水平的閱讀者都能有收獲,所以打算厚著臉皮將自己從中學(xué)到的一些知識點共享出來。打算從整體及分支,分章節(jié)剖析。本篇主要講 jQuery 的整體架構(gòu)及一些前期準(zhǔn)備,先來看看 jQuery 的整體結(jié)構(gòu):

jQuery 整體架構(gòu) 

不同于 jQuery 代碼各個模塊細節(jié)實現(xiàn)的晦澀難懂,jQuery 整體框架的結(jié)構(gòu)十分清晰,按代碼行文大致分為如上圖所示的模塊。

初看 jQuery 源碼可能很容易一頭霧水,因為 9000 行的代碼感覺沒有盡頭,所以了解作者的行文思路十分重要。

整體而言,我覺得 jQuery 采用的是總--分的結(jié)構(gòu),雖然JavaScript有著作用域的提升機制,但是 9000 多行的代碼為了相互的關(guān)聯(lián)性,并不代表所有的變量都要定義在最頂部。在 jQuery 中,只有全局都會用到的變量、正則表達式定義在了代碼最開頭,而每個模塊一開始,又會定義一些只在本模塊會使用到的變量、正則、方法等。所以在一開始的閱讀的過程中會有很多看不懂其作用的變量,正則,方法。

所以,我覺得閱讀源碼很重要的一點是,摒棄面向過程的思維方式,不要刻意去追求從上至下每一句都要在一開始弄明白。很有可能一開始你在一個奇怪的方法或者變量處卡殼了,很想知道這個方法或變量的作用,然而可能它要到幾千行處才被調(diào)用到。如果去追求這種逐字逐句弄清楚的方式,很有可能在碰壁幾次之后閱讀的積極性大受打擊。

道理說了很多,接來下進入真正的正文,對 jQurey 的一些前期準(zhǔn)備,小的細節(jié)進行分析:

jQuery 閉包結(jié)構(gòu)

 
 
 
 
  1. // 用一個函數(shù)域包起來,就是所謂的沙箱  
  2. // 在這里邊 var 定義的變量,屬于這個函數(shù)域內(nèi)的局部變量,避免污染全局  
  3. // 把當(dāng)前沙箱需要的外部變量通過函數(shù)參數(shù)引入進來  
  4. // 只要保證參數(shù)對內(nèi)提供的接口的一致性,你還可以隨意替換傳進來的這個參數(shù)  
  5. (function(window, undefined) {  
  6.    // jQuery 代碼  
  7. })(window);  

jQuery 具體的實現(xiàn),都被包含在了一個立即執(zhí)行函數(shù)構(gòu)造的閉包里面,為了不污染全局作用域,只在后面暴露 $ 和 jQuery 這 2 個變量給外界,盡量的避開變量沖突。常用的還有另一種寫法:

 
 
 
 
  1. (function(window) { 
  2.    // JS代碼 
  3. })(window, undefined); 

比較推崇的的第一種寫法,也就是 jQuery 的寫法。二者有何不同呢,當(dāng)我們的代碼運行在更早期的環(huán)境當(dāng)中(pre-ES5,eg. Internet Explorer 8),undefined 僅是一個變量且它的值是可以被蓋的。意味著你可以做這樣的操作:

 
 
 
 
  1. undefined = 42  
  2. console.log(undefined) // 42  

當(dāng)使用第一種方式,可以確保你需要的 undefined 確實就是 undefined。

另外不得不提出的是,jQuery 在這里有一個針對壓縮優(yōu)化細節(jié),使用第一種方式,在代碼壓縮的時候,window 和 undefined 都可以壓縮為 1 個字母并且確保它們就是 window 和 undefined.

 
 
 
 
  1. // 壓縮策略  
  2. // w -> windwow , u -> undefined  
  3. (function(w, u) {  
  4.    
  5. })(window);  

jQuery 無 new 構(gòu)造

 嘿,回想一下使用 jQuery 的時候,實例化一個 jQuery 對象的方法:

 
 
 
 
  1. // 無 new 構(gòu)造  
  2. $('#test').text('Test');  
  3.    
  4. // 當(dāng)然也可以使用 new  
  5. var test = new $('#test');  
  6. test.text('Test');  

大部分人使用 jQuery 的時候都是使用第一種無 new 的構(gòu)造方式,直接 $('') 進行構(gòu)造,這也是 jQuery 十分便捷的一個地方。當(dāng)我們使用第一種無 new 構(gòu)造方式的時候,其本質(zhì)就是相當(dāng)于 new jQuery(),那么在 jQuery 內(nèi)部是如何實現(xiàn)的呢?看看:

 
 
 
 
  1. (function(window, undefined) {  
  2.     var  
  3.     // ...  
  4.     jQuery = function(selector, context) {  
  5.         // The jQuery object is actually just the init constructor 'enhanced'  
  6.         // 看這里,實例化方法 jQuery() 實際上是調(diào)用了其拓展的原型方法 jQuery.fn.init  
  7.         return new jQuery.fn.init(selector, context, rootjQuery);  
  8.     },  
  9.    
  10.     // jQuery.prototype 即是 jQuery 的原型,掛載在上面的方法,即可讓所有生成的 jQuery 對象使用  
  11.     jQuery.fn = jQuery.prototype = {  
  12.         // 實例化化方法,這個方法可以稱作 jQuery 對象構(gòu)造器  
  13.         init: function(selector, context, rootjQuery) {  
  14.             // ...   
  15.         }  
  16.     }  
  17.     // 這一句很關(guān)鍵,也很繞  
  18.     // jQuery 沒有使用 new 運算符將 jQuery 實例化,而是直接調(diào)用其函數(shù)  
  19.     // 要實現(xiàn)這樣,那么 jQuery 就要看成一個類,且返回一個正確的實例  
  20.     // 且實例還要能正確訪問 jQuery 類原型上的屬性與方法  
  21.     // jQuery 的方式是通過原型傳遞解決問題,把 jQuery 的原型傳遞給jQuery.prototype.init.prototype  
  22.     // 所以通過這個方法生成的實例 this 所指向的仍然是 jQuery.fn,所以能正確訪問 jQuery 類原型上的屬性與方法  
  23.     jQuery.fn.init.prototype = jQuery.fn;  
  24.    
  25. })(window);  

部分人初看 jQuery.fn.init.prototype = jQuery.fn 這一句都會被卡主,很是不解。但是這句真的算是 jQuery 的絕妙之處。理解這幾句很重要,分點解析一下:

1)首先要明確,使用 $('xxx') 這種實例化方式,其內(nèi)部調(diào)用的是 return new jQuery.fn.init(selector, context, rootjQuery) 這一句話,也就是構(gòu)造實例是交給了 jQuery.fn.init() 方法去完成。

2)將 jQuery.fn.init 的 prototype 屬性設(shè)置為 jQuery.fn,那么使用 new jQuery.fn.init() 生成的對象的原型對象就是 jQuery.fn ,所以掛載到 jQuery.fn 上面的函數(shù)就相當(dāng)于掛載到 jQuery.fn.init() 生成的 jQuery 對象上,所有使用 new jQuery.fn.init() 生成的對象也能夠訪問到 jQuery.fn 上的所有原型方法。

3)也就是實例化方法存在這么一個關(guān)系鏈

  • jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype ;
  • new jQuery.fn.init() 相當(dāng)于 new jQuery() ;
  • jQuery() 返回的是 new jQuery.fn.init(),而 var obj = new jQuery(),所以這 2 者是相當(dāng)?shù)?,所以我們可以無 new 實例化 jQuery 對象。

jQuery 方法的重載

jQuery 源碼晦澀難讀的另一個原因是,使用了大量的方法重載,但是用起來卻很方便:

 
 
 
 
  1. // 獲取 title 屬性的值  
  2. $('#id').attr('title');  
  3. // 設(shè)置 title 屬性的值  
  4. $('#id').attr('title','jQuery');  
  5.    
  6. // 獲取 css 某個屬性的值  
  7. $('#id').css('title');  
  8. // 設(shè)置 css 某個屬性的值  
  9. $('#id').css('width','200px'); 

方法的重載即是一個方法實現(xiàn)多種功能,經(jīng)常又是 get 又是 set,雖然閱讀起來十分不易,但是從實用性的角度考慮,這也是為什么 jQuery 如此受歡迎的原因,大多數(shù)人使用 jQuery() 構(gòu)造方法使用的最多的就是直接實例化一個 jQuery 對象,但其實在它的內(nèi)部實現(xiàn)中,有著 9 種不同的方法重載場景:

 
 
 
 
  1. // 接受一個字符串,其中包含了用于匹配元素集合的 CSS 選擇器  
  2. jQuery([selector,[context]])  
  3. // 傳入單個 DOM   
  4. jQuery(element)  
  5. // 傳入 DOM 數(shù)組  
  6. jQuery(elementArray)  
  7. // 傳入 JS 對象  
  8. jQuery(object)  
  9. // 傳入 jQuery 對象  
  10. jQuery(jQuery object)  
  11. // 傳入原始 HTML 的字符串來創(chuàng)建 DOM 元素  
  12. jQuery(html,[ownerDocument])  
  13. jQuery(html,[attributes])  
  14. // 傳入空參數(shù)  
  15. jQuery()  
  16. // 綁定一個在 DOM 文檔載入完成后執(zhí)行的函數(shù)  
  17. jQuery(callback)  

以讀源碼的時候,很重要的一點是結(jié)合 jQuery API 進行閱讀,去了解方法重載了多少種功能,同時我想說的是,jQuery 源碼有些方法的實現(xiàn)特別長且繁瑣,因為 jQuery 本身作為一個通用性特別強的框架,一個方法兼容了許多情況,也允許用戶傳入各種不同的參數(shù),導(dǎo)致內(nèi)部處理的邏輯十分復(fù)雜,所以當(dāng)解讀一個方法的時候感覺到了明顯的困難,嘗試著跳出卡殼的那段代碼本身,站在更高的維度去思考這些復(fù)雜的邏輯是為了處理或兼容什么,是否是重載,為什么要這樣寫,一定會有不一樣的收獲。其次,也是因為這個原因,jQuery 源碼存在許多兼容低版本的 HACK 或者邏輯十分晦澀繁瑣的代碼片段,瀏覽器兼容這樣的大坑極其容易讓一個前端工程師不能學(xué)到編程的精髓,所以不要太執(zhí)著于一些邊角料,即使兼容性很重要,也應(yīng)該適度學(xué)習(xí)理解,適可而止。

jQuery.fn.extend 與 jQuery.extend

extend 方法在 jQuery 中是一個很重要的方法,jQuey 內(nèi)部用它來擴展靜態(tài)方法或?qū)嵗椒?,而且我們開發(fā) jQuery 插件開發(fā)的時候也會用到它。但是在內(nèi)部,是存在 jQuery.fn.extend 和 jQuery.extend 兩個 extend 方法的,而區(qū)分這兩個 extend 方法是理解 jQuery 的很關(guān)鍵的一部分。先看結(jié)論:

1)jQuery.extend(object) 為擴展 jQuery 類本身,為類添加新的靜態(tài)方法;

2)jQuery.fn.extend(object) 給 jQuery 對象添加實例方法,也就是通過這個 extend 添加的新方法,實例化的 jQuery 對象都能使用,因為它是掛載在 jQuery.fn 上的方法(上文有提到,jQuery.fn = jQuery.prototype )。

它們的官方解釋是:

1)jQuery.extend(): 把兩個或者更多的對象合并到第一個當(dāng)中,

2)jQuery.fn.extend():把對象掛載到 jQuery 的 prototype 屬性,來擴展一個新的 jQuery 實例方法。

也就是說,使用 jQuery.extend() 拓展的靜態(tài)方法,我們可以直接使用 $.xxx 進行調(diào)用(xxx是拓展的方法名),

而使用 jQuery.fn.extend() 拓展的實例方法,需要使用 $().xxx 調(diào)用。

 
 
 
 
  1. // 擴展合并函數(shù) 
  2. // 合并兩個或更多對象的屬性到第一個對象中,jQuery 后續(xù)的大部分功能都通過該函數(shù)擴展 
  3. // 雖然實現(xiàn)方式一樣,但是要注意區(qū)分用法的不一樣,那么為什么兩個方法指向同一個函數(shù)實現(xiàn),但是卻實現(xiàn)不同的功能呢, 
  4. // 閱讀源碼就能發(fā)現(xiàn)這歸功于 this 的強大力量 
  5. // 如果傳入兩個或多個對象,所有對象的屬性會被添加到第一個對象 target 
  6. // 如果只傳入一個對象,則將對象的屬性添加到 jQuery 對象中,也就是添加靜態(tài)方法 
  7. // 用這種方式,我們可以為 jQuery 命名空間增加新的方法,可以用于編寫 jQuery 插件 
  8. // 如果不想改變傳入的對象,可以傳入一個空對象:$.extend({}, object1, object2); 
  9. // 默認合并操作是不迭代的,即便 target 的某個屬性是對象或?qū)傩裕矔煌耆采w而不是合并 
  10. // 如果第一個參數(shù)是 true,則是深拷貝 
  11. // 從 object 原型繼承的屬性會被拷貝,值為 undefined 的屬性不會被拷貝 
  12. // 因為性能原因,JavaScript 自帶類型的屬性不會合并 
  13. jQuery.extend = jQuery.fn.extend = function() { 
  14.     var src, copyIsArray, copy, name, options, clone, 
  15.         target = arguments[0] || {}, 
  16.         i = 1, 
  17.         length = arguments.length, 
  18.         deep = false; 
  19.   
  20.     // Handle a deep copy situation 
  21.     // target 是傳入的第一個參數(shù) 
  22.     // 如果第一個參數(shù)是布爾類型,則表示是否要深遞歸, 
  23.     if (typeof target === "boolean") { 
  24.         deep = target; 
  25.         target = arguments[1] || {}; 
  26.         // skip the boolean and the target 
  27.         // 如果傳了類型為 boolean 的第一個參數(shù),i 則從 2 開始 
  28.         i = 2; 
  29.     } 
  30.   
  31.     // Handle case when target is a string or something (possible in deep copy) 
  32.     // 如果傳入的第一個參數(shù)是 字符串或者其他 
  33.     if (typeof target !== "object" && !jQuery.isFunction(target)) { 
  34.         target = {}; 
  35.     } 
  36.   
  37.     // extend jQuery itself if only one argument is passed 
  38.     // 如果參數(shù)的長度為 1 ,表示是 jQuery 靜態(tài)方法 
  39.     if (length === i) { 
  40.         target = this; 
  41.         --i; 
  42.     } 
  43.   
  44.     // 可以傳入多個復(fù)制源 
  45.     // i 是從 1或2 開始的 
  46.     for (; i < length; i++) { 
  47.         // Only deal with non-null/undefined values 
  48.         // 將每個源的屬性全部復(fù)制到 target 上 
  49.         if ((options = arguments[i]) != null) { 
  50.             // Extend the base object 
  51.             for (name in options) { 
  52.                 // src 是源(即本身)的值 
  53.                 // copy 是即將要復(fù)制過去的值 
  54.                 src = target[name]; 
  55.                 copy = options[name]; 
  56.   
  57.                 // Prevent never-ending loop 
  58.                 // 防止有環(huán),例如 extend(true, target, {'target':target}); 
  59.                 if (target === copy) { 
  60.                     continue; 
  61.                 } 
  62.   
  63.                 // Recurse if we're merging plain objects or arrays 
  64.                 // 這里是遞歸調(diào)用,最終都會到下面的 else if 分支 
  65.                 // jQuery.isPlainObject 用于測試是否為純粹的對象 
  66.                 // 純粹的對象指的是 通過 "{}" 或者 "new Object" 創(chuàng)建的 
  67.                 // 如果是深復(fù)制 
  68.                 if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) { 
  69.                     // 數(shù)組 
  70.                     if (copyIsArray) { 
  71.                         copyIsArray = false; 
  72.                         clone = src && jQuery.isArray(src) ? src : []; 
  73.   
  74.                         // 對象 
  75.                     } else { 
  76.                         clone = src && jQuery.isPlainObject(src) ? src : {}; 
  77.                     } 
  78.   
  79.                     // Never move original objects, clone them 
  80.                     // 遞歸 
  81.                     target[name] = jQuery.extend(deep, clone, copy); 
  82.   
  83.                     // Don't bring in undefined values 
  84.                     // 最終都會到這條分支 
  85.                     // 簡單的值覆蓋 
  86.                 } else if (copy !== undefined) { 
  87.                     target[name] = copy; 
  88.                 } 
  89.             } 
  90.         } 
  91.     } 
  92.   
  93.     // Return the modified object 
  94.     // 返回新的 target 
  95.     // 如果 i < length ,是直接返回沒經(jīng)過處理的 target,也就是 arguments[0] 
  96.     // 也就是如果不傳需要覆蓋的源,調(diào)用 $.extend 其實是增加 jQuery 的靜態(tài)方法 
  97.     return target; 
  98. }; 

需要注意的是這一句 jQuery.extend = jQuery.fn.extend = function() {} ,也就是 jQuery.extend 的實現(xiàn)和 jQuery.fn.extend 的實現(xiàn)共用了同一個方法,但是為什么能夠?qū)崿F(xiàn)不同的功能了,這就要歸功于 Javascript 強大(怪異?)的 this 了。

1)在 jQuery.extend() 中,this 的指向是 jQuery 對象(或者說是 jQuery 類),所以這里擴展在 jQuery 上;

2)在 jQuery.fn.extend() 中,this 的指向是 fn 對象,前面有提到 jQuery.fn = jQuery.prototype ,也就是這里增加的是原型方法,也就是對象方法。

jQuery 的鏈?zhǔn)秸{(diào)用及回溯

另一個讓大家喜愛使用 jQuery 的原因是它的鏈?zhǔn)秸{(diào)用,這一點的實現(xiàn)其實很簡單,只需要在要實現(xiàn)鏈?zhǔn)秸{(diào)用的方法的返回結(jié)果里,返回 this ,就能夠?qū)崿F(xiàn)鏈?zhǔn)秸{(diào)用了。

當(dāng)然,除了鏈?zhǔn)秸{(diào)用,jQuery 甚至還允許回溯,看看:

 
 
 
 
  1. // 通過 end() 方法終止在當(dāng)前鏈的最新過濾操作,返回上一個對象集合  
  2. $('div').eq(0).show().end().eq(1).hide();  

當(dāng)選擇了 ('div').eq(0) 之后使用 end() 可以回溯到上一步選中的 jQuery 對象 $('div'),其內(nèi)部實現(xiàn)其實是依靠添加了 prevObject 這個屬性:

jQuery 完整的鏈?zhǔn)秸{(diào)用、增棧、回溯通過 return this 、 return this.pushStack() 、return this.prevObject 實現(xiàn),看看源碼實現(xiàn):

 
 
 
 
  1. jQuery.fn = jQuery.prototype = {   
  2.     // 將一個 DOM 元素集合加入到 jQuery 棧  
  3.     // 此方法在 jQuery 的 DOM 操作中被頻繁的使用, 如在 parent(), find(), filter() 中  
  4.     // pushStack() 方法通過改變一個 jQuery 對象的 prevObject 屬性來跟蹤鏈?zhǔn)秸{(diào)用中前一個方法返回的 DOM 結(jié)果集合  
  5.     // 當(dāng)我們在鏈?zhǔn)秸{(diào)用 end() 方法后, 內(nèi)部就返回當(dāng)前 jQuery 對象的 prevObject 屬性  
  6.     pushStack: function(elems) {  
  7.         // 構(gòu)建一個新的jQuery對象,無參的 this.constructor(),只是返回引用this  
  8.         // jQuery.merge 把 elems 節(jié)點合并到新的 jQuery 對象  
  9.         // this.constructor 就是 jQuery 的構(gòu)造函數(shù) jQuery.fn.init,所以 this.constructor() 返回一個 jQuery 對象  
  10.         // 由于 jQuery.merge 函數(shù)返回的對象是第二個函數(shù)附加到第一個上面,所以 ret 也是一個 jQuery 對象,這里可以解釋為什么 pushStack 出入的 DOM 對象也可以用 CSS 方法進行操作  
  11.         var ret = jQuery.merge(this.constructor(), elems);  
  12.    
  13.         // 給返回的新 jQuery 對象添加屬性 prevObject  
  14.         // 所以也就是為什么通過 prevObject 能取到上一個合集的引用了  
  15.         ret.prevObject = this;  
  16.         ret.context = this.context;  
  17.    
  18.         // Return the newly-formed element set  
  19.         return ret;  
  20.     },  
  21.     // 回溯鏈?zhǔn)秸{(diào)用的上一個對象  
  22.     end: function() {  
  23.         // 回溯的關(guān)鍵是返回 prevObject 屬性  
  24.         // 而 prevObject 屬性保存了上一步操作的 jQuery 對象集合  
  25.         return this.prevObject || this.constructor(null);  
  26.     },  
  27.     // 取當(dāng)前 jQuery 對象的第 i 個  
  28.     eq: function(i) {  
  29.         // jQuery 對象集合的長度  
  30.         var len = this.length,  
  31.             j = +i + (i < 0 ? len : 0);  
  32.    
  33.         // 利用 pushStack 返回  
  34.         return this.pushStack(j >= 0 && j < len ? [this[j]] : []);  
  35.     },    
  36. }  

總的來說,

1)end() 方法返回 prevObject 屬性,這個屬性記錄了上一步操作的 jQuery 對象合集;

2)而 prevObject 屬性由 pushStack() 方法生成,該方法將一個 DOM 元素集合加入到 jQuery 內(nèi)部管理的一個棧中,通過改變 jQuery 對象的 prevObject 屬性來跟蹤鏈?zhǔn)秸{(diào)用中前一個方法返回的 DOM 結(jié)果集合

3)當(dāng)我們在鏈?zhǔn)秸{(diào)用 end() 方法后,內(nèi)部就返回當(dāng)前 jQuery 對象的 prevObject 屬性,完成回溯。

jQuery 正則與細節(jié)優(yōu)化

不得不提 jQuery 在細節(jié)優(yōu)化上做的很好。也存在很多值得學(xué)習(xí)的小技巧,下一篇將會以 jQuery 中的一些編程技巧為主題行文,這里就不再贅述。

然后想談?wù)務(wù)齽t表達式,jQuery 當(dāng)中用了大量的正則表達式,我覺得如果研讀 jQuery ,正則水平一定能夠大大提升,如果是個正則小白,我建議在閱讀之前先去了解以下幾點:

1)了解并嘗試使用 Javascript 正則相關(guān) API,包括了 test() 、replace() 、match() 、exec() 的用法;

2)區(qū)分上面 4 個方法,哪個是 RegExp 對象方法,哪個是 String 對象方法;

3)了解簡單的零寬斷言,了解什么是匹配但是不捕獲以及匹配并且捕獲。

jQuery 變量沖突處理

最后想提一提 jQuery 變量的沖突處理,通過一開始保存全局變量的 window.jQuery 以及 windw.$ 。

當(dāng)需要處理沖突的時候,調(diào)用靜態(tài)方法 noConflict(),讓出變量的控制權(quán),源碼如下:

 
 
 
 
  1. (function(window, undefined) {  
  2.     var  
  3.         // Map over jQuery in case of overwrite  
  4.         // 設(shè)置別名,通過兩個私有變量映射了 window 環(huán)境下的 jQuery 和 $ 兩個對象,以防止變量被強行覆蓋  
  5.         _jQuery = window.jQuery,  
  6.         _$ = window.$;  
  7.    
  8.     jQuery.extend({  
  9.         // noConflict() 方法讓出變量 $ 的 jQuery 控制權(quán),這樣其他腳本就可以使用它了  
  10.         // 通過全名替代簡寫的方式來使用 jQuery   
  11.         // deep -- 布爾值,指示是否允許徹底將 jQuery 變量還原(移交 $ 引用的同時是否移交 jQuery 對象本身)  
  12.         noConflict: function(deep) {  
  13.             // 判斷全局 $ 變量是否等于 jQuery 變量  
  14.             // 如果等于,則重新還原全局變量 $ 為 jQuery 運行之前的變量(存儲在內(nèi)部變量 _$ 中)  
  15.             if (window.$ === jQuery) {  
  16.                 // 此時 jQuery 別名 $ 失效  
  17.                 window.$ = _$;  
  18.             }  
  19.             // 當(dāng)開啟深度沖突處理并且全局變量 jQuery 等于內(nèi)部 jQuery,則把全局 jQuery 還原成之前的狀況  
  20.             if (deep && window.jQuery === jQuery) {  
  21.                 // 如果 deep 為 true,此時 jQuery 失效  
  22.                 window.jQuery = _jQuery;  
  23.             }  
  24.    
  25.             // 這里返回的是 jQuery 庫內(nèi)部的 jQuery 構(gòu)造函數(shù)(new jQuery.fn.init())   
  26.             // 像使用 $ 一樣盡情使用它吧  
  27.             return jQuery;  
  28.         }  
  29.     })  
  30. }(window)  

了一幅簡單的流程圖幫助理解:

那么讓出了這兩個符號之后,是否就不能在我們的代碼中使用 jQuery 或者呢 $ 呢?莫慌,還是可以使用的:

 
 
 
 
  1. // 讓出 jQuery 、$ 的控制權(quán)不代表不能使用 jQuery 和 $ ,方法如下:  
  2. var query = jQuery.noConflict(true);  
  3.    
  4. (function($) {   
  5.    
  6. // 插件或其他形式的代碼,也可以將參數(shù)設(shè)為 jQuery  
  7. })(query);  
  8.    
  9. //  ... 其他用 $ 作為別名的庫的代碼  

結(jié)束語

對 jQuery 整體架構(gòu)的一些解析就到這里,下一篇將會剖析一下 jQuery 中的一些優(yōu)化小技巧,一些對編程有所提高的地方。

原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,萬望告知。


分享題目:【深入淺出jQuery】源碼淺析--整體架構(gòu)
本文地址:http://www.5511xx.com/article/cddjjhg.html