標籤:continue 全域 out ext 作者 tar ase 說明 get
計劃按例如以下順序完畢這篇筆記:
- Java程式猿的JavaScript學習筆記(1——理念)
- Java程式猿的JavaScript學習筆記(2——屬性複製和繼承)
- Java程式猿的JavaScript學習筆記(3——this/call/apply)
- Java程式猿的JavaScript學習筆記(4——this/閉包/getter/setter)
- Java程式猿的JavaScript學習筆記(5——prototype)
- Java程式猿的JavaScript學習筆記(6——物件導向類比)
- Java程式猿的JavaScript學習筆記(7——jQuery基本機制)
- Java程式猿的JavaScript學習筆記(8——jQuery選取器)
- Java程式猿的JavaScript學習筆記(9——jQuery工具方法)
- Java程式猿的JavaScript學習筆記(10——jQuery-在“類”層面擴充)
- Java程式猿的JavaScript學習筆記(11——jQuery-在“對象”層面擴充)
- Java程式猿的JavaScript學習筆記(12——jQuery-延伸選取器)
- Java程式猿的JavaScript學習筆記(13——jQuery UI)
- Java程式猿的JavaScript學習筆記(14——擴充jQuery UI)
這是筆記的第9篇,從jQuery原始碼的角度。聊聊jQuery的工具方法。
作者部落格:http://blog.csdn.net/stationxp
作者微博:http://weibo.com/liuhailong2008
轉載請取得作者允許
1、先看幾個工具方法怎樣使用:
var t = $.trim(' >>_<< ');var ps = $.param({x:15,y:16});jQuery.type(function(){}) === "function"
jQuery的工具方法,相對jQuery本身,是相對獨立的。
2、這些方法是怎樣定義的呢?
我們推測一下,試試看。
我們知道jQuery(即$)是全域變數。這些方法應該是jQuery變數的屬性。
我們能夠通過例如以下文法加入:
jQuery.xx = function(a,b){ return a + b;}// tryvar r1 = jQuery.xx(2,3);console.log(r1);// output : 5var r2 = $.xx(3,3);console.log(r2);// output : 6上面代碼。說明$和jQuery引用了同樣變數,他們是一樣一樣的。
這些代碼達到了定義工具方法的目的,但jQuery是這樣做的嗎?
3、
查看jQuery源碼。jQuery通過例如以下文法定義工具方法:
jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) {window.$ = _$; } if ( deep && window.jQuery === jQuery ) {window.jQuery = _jQuery; } return jQuery; } //, ... });
extend方法定義例如以下:
//定義了一個方法,賦值給jQuery.fn.extend和jQuery.extend.//jQuery.fn.extend和jQuery.extend儘管定義同樣,但調用者不同,從而方法中this指向不同。從而實現的功能不同。//沒有顯式聲明參數,而是通過arguments動態獲得,從而支援更豐富的功能。jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, clone, // 將第一個參數作為目標對象 target = arguments[0] || {}, // i初始化為1,臨時還不知道做什麼用 i = 1, // length表示參數的個數 length = arguments.length, // deep 應該表示是否深層拷貝,默覺得否。 deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { //假設第一個參數是布爾類型,則第二個參數為目標對象 //形如:jQuery.extend(false,UiObject,...); deep = target; target = arguments[1] || {}; // i 是當前參數的數組下標,從0開始 i = 2; } //目標對象是能是函數或者對象,傳入其它參數,target默覺得Null 物件。
if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // 眼下,假設第一個參數不是布爾。i值為1。length也為1,即extend(obj)的情況 // 假設是布爾,i值為2,length也為2,即extend(true,obj)的情況 // 總之。沒有傳入 src if ( length === i ) { // jQuery 把傳入參數收了 // 參數下標又一次指向傳入的這個參數,即此時指向了src target = this; --i; } // 如今i指向了target後面某個參數。應該是src // 把後面傳入的每一個參數都當src for ( ;i < length; i++ ) { // Only deal with non-null/undefined values // 這樣過濾非空啊,假設是undefined會被過濾掉嗎? // 不做 typeof src 是否 "object"、"function"的推斷嗎? if ( (options = arguments[ i ]) != null ) { // 賦值給變數 options // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // 思慮萬全:假設已經是自家人,就別嘚瑟了 // Prevent never-ending loop if ( target === copy ) { continue; } // 對普通對象和數組。考慮遞迴深層拷貝 // 問題來了,什麼叫普通對象? function 算不算? if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { // 設下次迴圈的預設值 copyIsArray = false; // 目標對象假設原來有這個屬性。但不是數群組類型。就被幹掉了 clone = src && jQuery.isArray(src) ? src : []; } else { // 目標對象假設原來沒有這個屬性或者不是普通對象,默覺得{}。
// 假設已經有了並且是普通對象,那就用它了 clone = src && jQuery.isPlainObject(src) ? src : {}; } //遞迴調 //假設寫成 jQuery.extend( deep, clone, copy ) 是否一樣 // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values // 對 undefined 和 != null 還要加深理解 } else if ( copy !== undefined ) { // 臨門一腳。假設是 jQuery.extend({xx,xfasf});的情況。擴充的是this,即調用者。
// 對target直接改動。也沒建立clone啥的 target[ name ] = copy; } } } } // Return the modified object return target;};
4、再看看jQuery.isPlainObject怎樣定義的
isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well // 翻譯: // 必須是一個對象。 // 由於IE的緣故。我們還必須檢查是否有constructor屬性。
// 確認別放過Dom節點和window對象,他們不是普通對象。 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { // 下面不通過空、undefined、0、jQuery.type返回不是object的、dom對象、window對象 // 所以 typeof 為string、number、function、正則、date的都不成 return false; } try { // Not own constructor property must be Object if ( obj.constructor &&!core_hasOwn.call(obj, "constructor") &&!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // 枚舉的時候。自有屬性會先被枚舉出來。假設最後一個屬性是自有屬性。那麼全部屬性都是自有屬性。 // 簡而言之,不能有繼承來的。能夠被枚舉到的屬性,你妹。為什麼有這種要求? // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || core_hasOwn.call( obj, key ); }
5、
試試看
jQuery.extend({ <span style="white-space:pre"></span>sayHi:function(you){ <span style="white-space:pre"></span>console.log('hi',you); <span style="white-space:pre"></span>}});$.sayHi('Stanley'); // output : hi Stanley
還不錯!
假設想覆蓋jQuery已有的方法呢?
jQuery.extend({ isPlainObject:function(obj){return 'baby, I am not sure.'; }});var r = $.isPlainObject({});console.log(r); // output : baby, I am not sure.
這...好吧,能夠得逞。想想別的辦法吧,不能這樣。
再玩兒:
jQuery.extend({ extend:function(obj){ // do nothing return 'who am i?'; }});var r = $.extend({x:function(){ alert();}});console.log(r); // output : who am i?jQuery.x();// error : function not be defined
又得逞,這樣。再沒人能夠通過extend擴充jQuery的方法了。
但能夠有更直接的方法。
Java程式猿的JavaScript學習筆記(9—— jQuery工具方法)