摘要:通常的做法是,為它們指定回調函數。請求返回請求返回請求返回異步隊列解耦異步任務和回調函數為模塊隊列模塊事件提供基礎功能。
前言
jQuery整體框架甚是復雜,也不易讀懂,這幾日一直在研究這個笨重而強大的框架。jQuery的總體架構可以分為:入口模塊、底層模塊和功能模塊。這里,我們以jquery-1.7.1為例進行分析。
jquery的總體架構16 (function( window, undefined ) { // 構造 jQuery 對象 22 var jQuery = (function() { 25 var jQuery = function( selector, context ) { 27 return new jQuery.fn.init( selector, context, rootjQuery ); 28 }, // 一堆局部變量聲明 97 jQuery.fn = jQuery.prototype = { 98 constructor: jQuery, 99 init: function( selector, context, rootjQuery ) { ... }, // 一堆原型屬性和方法 319 }; 322 jQuery.fn.init.prototype = jQuery.fn; 324 jQuery.extend = jQuery.fn.extend = function() { ... }; 388 jQuery.extend({ // 一堆靜態屬性和方法 892 }); 955 return jQuery; 957 })(); // 省略其他模塊的代碼 ... 9246 window.jQuery = window.$ = jQuery; 9266 })( window );
分析一下以上代碼,我們發現jquery采取了匿名函數自執行的寫法,這樣做的好處就是可以有效的防止命名空間與變量污染的問題??s寫一下以上代碼就是:
(function(window, undefined) { var jQuery = function() {} // ... window.jQuery = window.$ = jQuery; })(window);參數window
匿名函數傳了兩個參數進來,一個是window,一個是undefined。我們知道,在js中變量是有作用域鏈的,這兩個變量的傳入就會變成匿名函數的局部變量,訪問起來的時候速度會更快。通過傳入window對象可以使window對象作為局部變量使用,那么,函數的參數也都變成了局部變量,當在jquery中訪問window對象時,就不需要將作用域鏈退回到頂層作用域,從而可以更快的訪問window對象。
參數undefinedjs在查找變量的時候,js引擎首先會在函數自身的作用域中查找這個變量,如果沒有的話就繼續往上找,找到了就返回該變量,找不到就返回undefined。undefined是window對象的一個屬性,通過傳入undefined參數,但又不進行賦值,可以縮短查找undefined時的作用域鏈。在 自調用匿名函數 的作用域內,確保undefined是真的未定義。因為undefined能夠被重寫,賦予新的值。
jquery.fn是啥?jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function( selector, context, rootjQuery ) { ... }, // 一堆原型屬性和方法 };
通過分析以上代碼,我們發現jQuery.fn即是jQuery.prototype,這樣寫的好處就是更加簡短吧。之后,我們又看到jquery為了簡潔,干脆使用一個$符號來代替jquery使用,因此,在我們使用jquery框架的使用經常都會用到$(),
構造函數jQuery()jQuery的對象并不是通過 new jQuery 創建的,而是通過 new jQuery.fn.init 創建的:
var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context, rootjQuery ); }
這里定義了一個變量jQuery,他的值是jQuery構造函數,在955行(最上面的代碼)返回并賦值給jQuery變量
jQuery.fn.initjQuery.fn (上面97行)是構造函數jQuery()的原型對象,jQuery.fn.init()是jQuery原型方法,也可以稱作構造函數。負責解析參數selector和context的類型并執行相應的查找。
參數context:可以不傳入,或者傳入jQuery對象,DOM元素,普通js對象之一
參數rootjQuery:包含了document對象的jQuery對象,用于document.getElementById()查找失敗等情況。
jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
jQuery(selector [,context])
默認情況下,對匹配元素的查找從根元素document 對象開始,即查找范圍是整個文檔樹,不過也可以傳入第二個參數context來限定它的查找范圍。例如:
$("div.foo").click(function () { $("span",this).addClass("bar");//限定查找范圍,即上面的context });$.extend()和$.fn.extend()
方法jQuery.extend(object)和jQuery.fn.extend(object)用于合并兩個或多個對象到第一個對象。相關源代碼如下(部分):
jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone,//定義的一組局部變量 target = arguments[0] || {}, i = 1, length = arguments.length, deep = false;
相關變量含義如下:
變量options:指向某個源對象 變量name:表示目標對象的某個屬性名 變量src:表示目標對象的某個屬性的原始值 變量copy:表示某個源對象的某個屬性的值 變量copyIsArray:指示變量copy是否是數組 變量clone:表示深度復制時原始值的修正值 變量target:指向目標對象 變量i:表示源對象的起始下標 變量length:表示參數的個數,用于修正變量 變量deep:指示是否執行深度復制,默認為false
jQuery.extend(object); 為jQuery類添加添加類方法,可以理解為添加靜態方法。如:
$.extend({ add:function(a,b){ return a+b; } });
便為 jQuery 添加一個為add 的 “靜態方法”,之后便可以在引入 jQuery 的地方,使用這個方法了, 就是將add方法合并到jquery的全局對象中。
$.add(3,4); //return 7
jQuery.fn.extend(object),查看一段官網的代碼演示如下:
看下面一個jQuery對象的擴展方法:
$.fn.extend({ sayHello : function(){ alert("hello"); } });
就是將sayHello方法合并到jquery的實例對象中
CSS選擇器引擎 Sizzle可以說,jQuery是為操作DOM而誕生的,jQuery之所以如此強大,得益于CSS選擇器引擎 Sizzle,解析規則引用網上的一段實例:
selector:"div > p + div.aaron input[type="checkbox"]" 解析規則: 1 按照從右到左 2 取出最后一個token 比如[type="checkbox"] { matches : Array[3] type : "ATTR" value : "[type=" checkbox "]" } 3 過濾類型 如果type是 > + ~ 空 四種關系選擇器中的一種,則跳過,在繼續過濾 4 直到匹配到為 ID,CLASS,TAG 中一種 , 因為這樣才能通過瀏覽器的接口索取 5 此時seed種子合集中就有值了,這樣把刷選的條件給縮的很小了 6 如果匹配的seed的合集有多個就需要進一步的過濾了,修正選擇器 selector: "div > p + div.aaron [type="checkbox"]" 7 OK,跳到一下階段的編譯函數deferred對象
開發網站的過程中,我們經常遇到某些耗時很長的javascript操作。其中,既有異步的操作(比如ajax讀取服務器數據),也有同步的操作(比如遍歷一個大型數組),它們都不是立即能得到結果的。
通常的做法是,為它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。
但是,在回調函數方面,jQuery的功能非常弱。為了改變這一點,jQuery開發團隊就設計了deferred對象。
簡單說,deferred對象就是jQuery的回調函數解決方案。在英語中,defer的意思是"延遲",所以deferred對象的含義就是"延遲"到未來某個點再執行。
回顧一下jQuery的ajax操作的傳統寫法:
$.ajax({ url: "test.html", success: function(){ alert("哈哈,成功了!"); }, error:function(){ alert("出錯啦!"); } });
在上面的代碼中,$.ajax()接受一個對象參數,這個對象包含兩個方法:success方法指定操作成功后的回調函數,error方法指定操作失敗后的回調函數。
$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR對象,你沒法進行鏈式操作;如果高于1.5.0版本,返回的是deferred對象,可以進行鏈式操作。
現在,新的寫法是這樣的:
$.ajax("test.html") .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出錯啦!"); });為多個操作指定回調函數
deferred對象的另一大好處,就是它允許你為多個事件指定一個回調函數,這是傳統寫法做不到的。
請看下面的代碼,它用到了一個新的方法$.when():
$.when($.ajax("test1.html"), $.ajax("test2.html")) .done(function(){ alert("哈哈,成功了!"); }) .fail(function(){ alert("出錯啦!"); });
這段代碼的意思是,先執行兩個操作$.ajax("test1.html")和$.ajax("test2.html"),如果都成功了,就運行done()指定的回調函數;如果有一個失敗或都失敗了,就執行fail()指定的回調函數。
jQuery.Deferred( func ) 的實現原理內部維護了三個回調函數列表:成功回調函數列表、失敗回調函數列表、消息回調函數列表,其他方法則圍繞這三個列表進行操作和檢測。
jQuery.Deferred( func ) 的源碼結構:
jQuery.extend({ Deferred: function( func ) { // 成功回調函數列表 var doneList = jQuery.Callbacks( "once memory" ), // 失敗回調函數列表 failList = jQuery.Callbacks( "once memory" ), // 消息回調函數列表 progressList = jQuery.Callbacks( "memory" ), // 初始狀態 state = "pending", // 異步隊列的只讀副本 promise = { // done, fail, progress // state, isResolved, isRejected // then, always // pipe // promise }, // 異步隊列 deferred = promise.promise({}), key; // 添加觸發成功、失敗、消息回調函列表的方法 for ( key in lists ) { deferred[ key ] = lists[ key ].fire; deferred[ key + "With" ] = lists[ key ].fireWith; } // 添加設置狀態的回調函數 deferred.done( function() { state = "resolved"; }, failList.disable, progressList.lock ) .fail( function() { state = "rejected"; }, doneList.disable, progressList.lock ); // 如果傳入函數參數 func,則執行。 if ( func ) { func.call( deferred, deferred ); } // 返回異步隊列 deferred return deferred; }, } jQuery.when( deferreds ) 提供了基于一個或多個對象的狀態來執行回調函數的功能,通常是基于具有異步事件的異步隊列。 jQuery.when( deferreds ) 的用法 如果傳入多個異步隊列對象,方法 jQuery.when() 返回一個新的主異步隊列對象的只讀副本,只讀副本將跟蹤所傳入的異步隊列的最終狀態。 一旦所有異步隊列都變為成功狀態,“主“異步隊列的成功回調函數被調用; 如果其中一個異步隊列變為失敗狀態,主異步隊列的失敗回調函數被調用。 /* 請求 "/when.do?method=when1" 返回 {"when":1} 請求 "/when.do?method=when2" 返回 {"when":2} 請求 "/when.do?method=when3" 返回 {"when":3} */ var whenDone = function(){ console.log( "done", arguments ); }, whenFail = function(){ console.log( "fail", arguments ); }; $.when( $.ajax( "/when.do?method=when1", { dataType: "json" } ), $.ajax( "/when.do?method=when2", { dataType: "json" } ), $.ajax( "/when.do?method=when3", { dataType: "json" } ) ).done( whenDone ).fail( whenFail );
異步隊列 Deferred
解耦異步任務和回調函數
為 ajax 模塊、隊列模塊、ready 事件提供基礎功能。
原型屬性和方法原型屬性和方法源代碼:
97 jQuery.fn = jQuery.prototype = { 98 constructor: jQuery, 99 init: function( selector, context, rootjQuery ) {} 210 selector: "", 213 jquery: "1.7.1", 216 length: 0, 219 size: function() {}, 223 toArray: function() {}, 229 get: function( num ) {}, 241 pushStack: function( elems, name, selector ) {}, 270 each: function( callback, args ) {}, 274 ready: function( fn ) {}, // 284 eq: function( i ) {}, 291 first: function() {}, 295 last: function() {}, 299 slice: function() {}, 304 map: function( callback ) {}, 310 end: function() {}, 316 push: push, 317 sort: [].sort, 318 splice: [].splice 319 };
屬性selector用于記錄jQuery查找和過濾DOM元素時的選擇器表達式。
屬性.length表示當前jquery對象中元素的個數。
方法.size()返回當前jquery對象中元素的個數,功能上等同于屬性length,但應該優先使用length,因為他沒有函數調用開銷。
.size()源碼如下:
size():function(){ return this.length; }
方法.toArray()將當前jQuery對象轉換為真正的數組,轉換后的數組包含了所有元素,其源碼如下:
toArray: function() { return slice.call( this ); },
方法.get(index)返回當前jQuery對象中指定位置的元素,或包含了全部元素的數組。其源
碼如下:
get: function( num ) { return num == null ? // Return a "clean" array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); },
如果沒有傳入參數,則調用.toArray()返回了包含有鎖元素的數組;如果指定了參數index,則返回一個多帶帶的元素,index從0開始計數,并且支持負數。
首先會判斷num是否小于0,如果小于0,則用length+num重新計算下標,然后使用數組訪問操作符([])獲取指定位置的元素,這是支持下標為負數的一個小技巧;如果大于等于0,直接返回指定位置的元素。
eg()和get()使用詳解:http://segmentfault.com/blog/...
方法.each()用于遍歷當前jQuery對象,并在每個元素上執行回調函數。方法.each()內部通過簡單的調用靜態方法jQuery.each()實現:
each: function( callback, args ) { return jQuery.each( this, callback, args ); },
回調函數是在當前元素為上下文的語境中觸發的,即關鍵字this總是指向當前元素,在回調函數中return false 可以終止遍歷。
方法.map()遍歷當前jQuery對象,在每個元素上執行回調函數,并將回調函數的返回值放入一個新jQuery對象中。該方法常用于獲取或設置DOM元素集合的值。
map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); },
原型方法.pushStack()創建一個新的空jQuery對象,然后把DOM元素集合放入這個jQuery對象中,并保留對當前jQuery對象的引用。
原型方法.pushStack()是核心方法之一,它為以下方法提供支持:
jQuery對象遍歷:.eq()、.first()、.last()、.slice()、.map()。 DOM查找、過濾:.find()、.not()、.filter()、.closest()、.add()、.andSelf()。 DOM遍歷:.parent()、.parents()、.parentsUntil()、.next()、.prev()、.nextAll()、.prevAll()、.nextUnit()、.prevUnit()、.siblings()、.children()、.contents()。 DOM插入:jQuery.before()、jQuery.after()、jQuery.replaceWith()、.append()、.prepent()、.before()、.after()、.replaceWith()。
定義方法.push( elems, name, selector ),它接受3個參數:
參數elems:將放入新jQuery對象的元素數組(或類數組對象)。 參數name:產生元素數組elems的jQuery方法名。 參數selector:傳給jQuery方法的參數,用于修正原型屬性.selector。
方法.end()結束當前鏈條中最近的篩選操作,并將匹配元素還原為之前的狀態
end: function() { return this.prevObject || this.constructor(null); },
返回前一個jQuery對象,如果屬性prevObect不存在,則構建一個空的jQuery對象返回。方法.pushStack()用于入棧,方法.end()用于出棧
靜態屬性和方法相關源碼如下:
388 jQuery.extend({ 389 noConflict: function( deep ) {}, 402 isReady: false, 406 readyWait: 1, 409 holdReady: function( hold ) {}, 418 ready: function( wait ) {}, 444 bindReady: function() {}, 492 isFunction: function( obj ) {}, 496 isArray: Array.isArray || function( obj ) {}, 501 isWindow: function( obj ) {}, 505 isNumeric: function( obj ) {}, 509 type: function( obj ) {}, 515 isPlainObject: function( obj ) {}, 544 isEmptyObject: function( obj ) {}, 551 error: function( msg ) {}, 555 parseJSON: function( data ) {}, 581 parseXML: function( data ) {}, 601 noop: function() {}, 606 globalEval: function( data ) {}, 619 camelCase: function( string ) {}, 623 nodeName: function( elem, name ) {}, 628 each: function( object, callback, args ) {}, 669 trim: trim ? function( text ) {} : function( text ) {}, 684 makeArray: function( array, results ) {}, 702 inArray: function( elem, array, i ) {}, 724 merge: function( first, second ) {}, 744 grep: function( elems, callback, inv ) {}, 761 map: function( elems, callback, arg ) {}, 794 guid: 1, 798 proxy: function( fn, context ) {}, 825 access: function( elems, key, value, exec, fn, pass ) {}, 852 now: function() {}, 858 uaMatch: function( ua ) {}, 870 sub: function() {}, 891 browser: {} 892 });
方法jQuery.noConflict([removeAll])用于釋放jQuery對全局變量$的控制權,可選參數removeAll指示是否釋放對全局變量jQuery的控制權。
在使用jQuery的同時,如果需要使用另一個javascript庫,可以調用$.noConflict()返回$給其他庫
方法jQuery.isFunction(obj)用于判斷傳入的參數是否是函數;
方法jQuery.isArray(obj)用于判斷傳入的參數是否是數組。
這兩個方法的實現依賴于jQuer.type(obj),通過判斷jQuery.type(obj)返回值是否是function和array來實現
相關源碼如下:
492 isFunction : function(obj){ 493 return jQuery.type(obj) === "function"; 494 }, 495 496 isArray: Array.isArray || function(obj){ 497 return jQuery.type(obj) === "array"; 498 },
方法jQuery.type(obj)用于判斷參數的內建JavaScript類型。如果參數是undefined 或 null ,返回 undefined 或 null;如果參數是JavaScript內部對象,則返回對象
的字符串名稱;其他情況一律返回object,相關源碼如下:
509 type :function(obj){ 510 return obj == null ? 511 String( obj ) : 512 class2type[toString.call(obj)] || "object"; 513 },
方法jQuery.isWindow(obj)用于判斷傳入的參數是否是window對象,通過檢測是否存在特征屬性setInterval來實現,相關代碼如下:
501 isWindow: function(obj){ 502 return obj && typeof obj ==="object" && "setInterval" in obj; 503 },
本人兼職前端付費技術顧問,如需幫助請加本人微信hawx1993,非誠勿擾
1.為初學前端而不知道怎么做項目的你指導 2.指導并扎實你的JavaScript基礎 3.幫你準備面試并提供相關指導性意見 4.為你的前端之路提供極具建設性的意見 5.讓你的學習更有效率,對知識點的理解更加透徹 6.不解答可以百度到的答案,也不解答你遇到的bug 付費(每月僅需99)能讓我更有耐心和責任心的為你指導,讓雙方產生更良好的協作
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85362.html
摘要:就是內部作為全局函數的插件添加到內核上去的。選擇器插件擴充自己喜歡的一些選擇器。在插件里的,經過了一些封裝處理,就是表示對象。調用時,字體大小會運用插件里的默認值 jQuery插件的分類 jQuery插件有很多,有UI類,表單驗證,輸入類,特效類,Ajax類,滑動類,導航類,工具類,動畫類等等。 jQuery的插件主要分為三類: 1、封裝對象方法的插件:也就是基于某個DOM元素的...
摘要:文章出處拜讀一個開源框架,最想學到的就是設計的思想和實現的技巧。利用下的簡單工廠模式,來將所有對于同一個對象的操作指定同一個實例。所以的中提供了以上中擴展函數。 文章出處 http://www.cnblogs.com/aaronjs/p/3278578.html 拜讀一個開源框架,最想學到的就是設計的思想和實現的技巧。 廢話不多說,jquery這么多年了分析都寫爛了,老早以前就拜讀過,...
摘要:大潮來襲前端開發能做些什么去年谷歌和火狐針對提出了的標準,顧名思義,即的體驗方式,我們可以戴著頭顯享受沉浸式的網頁,新的標準讓我們可以使用語言來開發。 VR 大潮來襲 --- 前端開發能做些什么 去年谷歌和火狐針對 WebVR 提出了 WebVR API 的標準,顧名思義,WebVR 即 web + VR 的體驗方式,我們可以戴著頭顯享受沉浸式的網頁,新的 API 標準讓我們可以使用 ...
摘要:支持形式的調用這其實是非常經典的無構造,其實就是一個構造函數,的結果就是一個對象實例,該實例有個屬性,屬性值是。 前言 終于,樓主的「Underscore 源碼解讀系列」underscore-analysis 即將進入尾聲,關注下 timeline 會發現樓主最近加快了解讀速度。十一月,多事之秋,最近好多事情搞的樓主心力憔悴,身心俱疲,也想盡快把這個系列完結掉,也好了卻一件心事。 本文...
閱讀 763·2019-08-29 12:49
閱讀 3550·2019-08-29 11:32
閱讀 3434·2019-08-26 10:43
閱讀 2402·2019-08-23 16:53
閱讀 2048·2019-08-23 15:56
閱讀 1695·2019-08-23 12:03
閱讀 2767·2019-08-23 11:25
閱讀 2084·2019-08-22 15:11