新聞中心
最近一直在研讀 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)
- // 用一個函數(shù)域包起來,就是所謂的沙箱
- // 在這里邊 var 定義的變量,屬于這個函數(shù)域內(nèi)的局部變量,避免污染全局
- // 把當(dāng)前沙箱需要的外部變量通過函數(shù)參數(shù)引入進來
- // 只要保證參數(shù)對內(nèi)提供的接口的一致性,你還可以隨意替換傳進來的這個參數(shù)
- (function(window, undefined) {
- // jQuery 代碼
- })(window);
jQuery 具體的實現(xiàn),都被包含在了一個立即執(zhí)行函數(shù)構(gòu)造的閉包里面,為了不污染全局作用域,只在后面暴露 $ 和 jQuery 這 2 個變量給外界,盡量的避開變量沖突。常用的還有另一種寫法:
- (function(window) {
- // JS代碼
- })(window, undefined);
比較推崇的的第一種寫法,也就是 jQuery 的寫法。二者有何不同呢,當(dāng)我們的代碼運行在更早期的環(huán)境當(dāng)中(pre-ES5,eg. Internet Explorer 8),undefined 僅是一個變量且它的值是可以被蓋的。意味著你可以做這樣的操作:
- undefined = 42
- console.log(undefined) // 42
當(dāng)使用第一種方式,可以確保你需要的 undefined 確實就是 undefined。
另外不得不提出的是,jQuery 在這里有一個針對壓縮優(yōu)化細節(jié),使用第一種方式,在代碼壓縮的時候,window 和 undefined 都可以壓縮為 1 個字母并且確保它們就是 window 和 undefined.
- // 壓縮策略
- // w -> windwow , u -> undefined
- (function(w, u) {
- })(window);
jQuery 無 new 構(gòu)造
嘿,回想一下使用 jQuery 的時候,實例化一個 jQuery 對象的方法:
- // 無 new 構(gòu)造
- $('#test').text('Test');
- // 當(dāng)然也可以使用 new
- var test = new $('#test');
- 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)的呢?看看:
- (function(window, undefined) {
- var
- // ...
- jQuery = function(selector, context) {
- // The jQuery object is actually just the init constructor 'enhanced'
- // 看這里,實例化方法 jQuery() 實際上是調(diào)用了其拓展的原型方法 jQuery.fn.init
- return new jQuery.fn.init(selector, context, rootjQuery);
- },
- // jQuery.prototype 即是 jQuery 的原型,掛載在上面的方法,即可讓所有生成的 jQuery 對象使用
- jQuery.fn = jQuery.prototype = {
- // 實例化化方法,這個方法可以稱作 jQuery 對象構(gòu)造器
- init: function(selector, context, rootjQuery) {
- // ...
- }
- }
- // 這一句很關(guān)鍵,也很繞
- // jQuery 沒有使用 new 運算符將 jQuery 實例化,而是直接調(diào)用其函數(shù)
- // 要實現(xiàn)這樣,那么 jQuery 就要看成一個類,且返回一個正確的實例
- // 且實例還要能正確訪問 jQuery 類原型上的屬性與方法
- // jQuery 的方式是通過原型傳遞解決問題,把 jQuery 的原型傳遞給jQuery.prototype.init.prototype
- // 所以通過這個方法生成的實例 this 所指向的仍然是 jQuery.fn,所以能正確訪問 jQuery 類原型上的屬性與方法
- jQuery.fn.init.prototype = jQuery.fn;
- })(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 源碼晦澀難讀的另一個原因是,使用了大量的方法重載,但是用起來卻很方便:
- // 獲取 title 屬性的值
- $('#id').attr('title');
- // 設(shè)置 title 屬性的值
- $('#id').attr('title','jQuery');
- // 獲取 css 某個屬性的值
- $('#id').css('title');
- // 設(shè)置 css 某個屬性的值
- $('#id').css('width','200px');
方法的重載即是一個方法實現(xiàn)多種功能,經(jīng)常又是 get 又是 set,雖然閱讀起來十分不易,但是從實用性的角度考慮,這也是為什么 jQuery 如此受歡迎的原因,大多數(shù)人使用 jQuery() 構(gòu)造方法使用的最多的就是直接實例化一個 jQuery 對象,但其實在它的內(nèi)部實現(xiàn)中,有著 9 種不同的方法重載場景:
- // 接受一個字符串,其中包含了用于匹配元素集合的 CSS 選擇器
- jQuery([selector,[context]])
- // 傳入單個 DOM
- jQuery(element)
- // 傳入 DOM 數(shù)組
- jQuery(elementArray)
- // 傳入 JS 對象
- jQuery(object)
- // 傳入 jQuery 對象
- jQuery(jQuery object)
- // 傳入原始 HTML 的字符串來創(chuàng)建 DOM 元素
- jQuery(html,[ownerDocument])
- jQuery(html,[attributes])
- // 傳入空參數(shù)
- jQuery()
- // 綁定一個在 DOM 文檔載入完成后執(zhí)行的函數(shù)
- 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)用。
- // 擴展合并函數(shù)
- // 合并兩個或更多對象的屬性到第一個對象中,jQuery 后續(xù)的大部分功能都通過該函數(shù)擴展
- // 雖然實現(xiàn)方式一樣,但是要注意區(qū)分用法的不一樣,那么為什么兩個方法指向同一個函數(shù)實現(xiàn),但是卻實現(xiàn)不同的功能呢,
- // 閱讀源碼就能發(fā)現(xiàn)這歸功于 this 的強大力量
- // 如果傳入兩個或多個對象,所有對象的屬性會被添加到第一個對象 target
- // 如果只傳入一個對象,則將對象的屬性添加到 jQuery 對象中,也就是添加靜態(tài)方法
- // 用這種方式,我們可以為 jQuery 命名空間增加新的方法,可以用于編寫 jQuery 插件
- // 如果不想改變傳入的對象,可以傳入一個空對象:$.extend({}, object1, object2);
- // 默認合并操作是不迭代的,即便 target 的某個屬性是對象或?qū)傩裕矔煌耆采w而不是合并
- // 如果第一個參數(shù)是 true,則是深拷貝
- // 從 object 原型繼承的屬性會被拷貝,值為 undefined 的屬性不會被拷貝
- // 因為性能原因,JavaScript 自帶類型的屬性不會合并
- jQuery.extend = jQuery.fn.extend = function() {
- var src, copyIsArray, copy, name, options, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
- // Handle a deep copy situation
- // target 是傳入的第一個參數(shù)
- // 如果第一個參數(shù)是布爾類型,則表示是否要深遞歸,
- if (typeof target === "boolean") {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- // 如果傳了類型為 boolean 的第一個參數(shù),i 則從 2 開始
- i = 2;
- }
- // Handle case when target is a string or something (possible in deep copy)
- // 如果傳入的第一個參數(shù)是 字符串或者其他
- if (typeof target !== "object" && !jQuery.isFunction(target)) {
- target = {};
- }
- // extend jQuery itself if only one argument is passed
- // 如果參數(shù)的長度為 1 ,表示是 jQuery 靜態(tài)方法
- if (length === i) {
- target = this;
- --i;
- }
- // 可以傳入多個復(fù)制源
- // i 是從 1或2 開始的
- for (; i < length; i++) {
- // Only deal with non-null/undefined values
- // 將每個源的屬性全部復(fù)制到 target 上
- if ((options = arguments[i]) != null) {
- // Extend the base object
- for (name in options) {
- // src 是源(即本身)的值
- // copy 是即將要復(fù)制過去的值
- src = target[name];
- copy = options[name];
- // Prevent never-ending loop
- // 防止有環(huán),例如 extend(true, target, {'target':target});
- if (target === copy) {
- continue;
- }
- // Recurse if we're merging plain objects or arrays
- // 這里是遞歸調(diào)用,最終都會到下面的 else if 分支
- // jQuery.isPlainObject 用于測試是否為純粹的對象
- // 純粹的對象指的是 通過 "{}" 或者 "new Object" 創(chuàng)建的
- // 如果是深復(fù)制
- if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
- // 數(shù)組
- if (copyIsArray) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
- // 對象
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
- // Never move original objects, clone them
- // 遞歸
- target[name] = jQuery.extend(deep, clone, copy);
- // Don't bring in undefined values
- // 最終都會到這條分支
- // 簡單的值覆蓋
- } else if (copy !== undefined) {
- target[name] = copy;
- }
- }
- }
- }
- // Return the modified object
- // 返回新的 target
- // 如果 i < length ,是直接返回沒經(jīng)過處理的 target,也就是 arguments[0]
- // 也就是如果不傳需要覆蓋的源,調(diào)用 $.extend 其實是增加 jQuery 的靜態(tài)方法
- return target;
- };
需要注意的是這一句 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 甚至還允許回溯,看看:
- // 通過 end() 方法終止在當(dāng)前鏈的最新過濾操作,返回上一個對象集合
- $('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):
- jQuery.fn = jQuery.prototype = {
- // 將一個 DOM 元素集合加入到 jQuery 棧
- // 此方法在 jQuery 的 DOM 操作中被頻繁的使用, 如在 parent(), find(), filter() 中
- // pushStack() 方法通過改變一個 jQuery 對象的 prevObject 屬性來跟蹤鏈?zhǔn)秸{(diào)用中前一個方法返回的 DOM 結(jié)果集合
- // 當(dāng)我們在鏈?zhǔn)秸{(diào)用 end() 方法后, 內(nèi)部就返回當(dāng)前 jQuery 對象的 prevObject 屬性
- pushStack: function(elems) {
- // 構(gòu)建一個新的jQuery對象,無參的 this.constructor(),只是返回引用this
- // jQuery.merge 把 elems 節(jié)點合并到新的 jQuery 對象
- // this.constructor 就是 jQuery 的構(gòu)造函數(shù) jQuery.fn.init,所以 this.constructor() 返回一個 jQuery 對象
- // 由于 jQuery.merge 函數(shù)返回的對象是第二個函數(shù)附加到第一個上面,所以 ret 也是一個 jQuery 對象,這里可以解釋為什么 pushStack 出入的 DOM 對象也可以用 CSS 方法進行操作
- var ret = jQuery.merge(this.constructor(), elems);
- // 給返回的新 jQuery 對象添加屬性 prevObject
- // 所以也就是為什么通過 prevObject 能取到上一個合集的引用了
- ret.prevObject = this;
- ret.context = this.context;
- // Return the newly-formed element set
- return ret;
- },
- // 回溯鏈?zhǔn)秸{(diào)用的上一個對象
- end: function() {
- // 回溯的關(guān)鍵是返回 prevObject 屬性
- // 而 prevObject 屬性保存了上一步操作的 jQuery 對象集合
- return this.prevObject || this.constructor(null);
- },
- // 取當(dāng)前 jQuery 對象的第 i 個
- eq: function(i) {
- // jQuery 對象集合的長度
- var len = this.length,
- j = +i + (i < 0 ? len : 0);
- // 利用 pushStack 返回
- return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
- },
- }
總的來說,
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),源碼如下:
- (function(window, undefined) {
- var
- // Map over jQuery in case of overwrite
- // 設(shè)置別名,通過兩個私有變量映射了 window 環(huán)境下的 jQuery 和 $ 兩個對象,以防止變量被強行覆蓋
- _jQuery = window.jQuery,
- _$ = window.$;
- jQuery.extend({
- // noConflict() 方法讓出變量 $ 的 jQuery 控制權(quán),這樣其他腳本就可以使用它了
- // 通過全名替代簡寫的方式來使用 jQuery
- // deep -- 布爾值,指示是否允許徹底將 jQuery 變量還原(移交 $ 引用的同時是否移交 jQuery 對象本身)
- noConflict: function(deep) {
- // 判斷全局 $ 變量是否等于 jQuery 變量
- // 如果等于,則重新還原全局變量 $ 為 jQuery 運行之前的變量(存儲在內(nèi)部變量 _$ 中)
- if (window.$ === jQuery) {
- // 此時 jQuery 別名 $ 失效
- window.$ = _$;
- }
- // 當(dāng)開啟深度沖突處理并且全局變量 jQuery 等于內(nèi)部 jQuery,則把全局 jQuery 還原成之前的狀況
- if (deep && window.jQuery === jQuery) {
- // 如果 deep 為 true,此時 jQuery 失效
- window.jQuery = _jQuery;
- }
- // 這里返回的是 jQuery 庫內(nèi)部的 jQuery 構(gòu)造函數(shù)(new jQuery.fn.init())
- // 像使用 $ 一樣盡情使用它吧
- return jQuery;
- }
- })
- }(window)
了一幅簡單的流程圖幫助理解:
那么讓出了這兩個符號之后,是否就不能在我們的代碼中使用 jQuery 或者呢 $ 呢?莫慌,還是可以使用的:
- // 讓出 jQuery 、$ 的控制權(quán)不代表不能使用 jQuery 和 $ ,方法如下:
- var query = jQuery.noConflict(true);
- (function($) {
- // 插件或其他形式的代碼,也可以將參數(shù)設(shè)為 jQuery
- })(query);
- // ... 其他用 $ 作為別名的庫的代碼
結(jié)束語
對 jQuery 整體架構(gòu)的一些解析就到這里,下一篇將會剖析一下 jQuery 中的一些優(yōu)化小技巧,一些對編程有所提高的地方。
原創(chuàng)文章,文筆有限,才疏學(xué)淺,文中若有不正之處,萬望告知。
分享題目:【深入淺出jQuery】源碼淺析--整體架構(gòu)
本文地址:http://www.5511xx.com/article/cddjjhg.html


咨詢
建站咨詢
