jQuery作為前端最流行的類庫,沒有之一,源碼必須得讀一讀。本博将不定期更新源碼解讀内容,如果解讀不正确的地方,還請同學們在評論中指正。
本系列文章基于jquery-1.9.1.js。(編者注:雖然JQ已經出到2.X,本文所述的方法是基本方法,沒有版本之差,對于學習有所幫助)
一、$.type() 判斷js資料類型
用法:$.type(new Array()); //array
部份源碼(截取關鍵部份,請忽略源碼文法):
//生成typelist的map
class2type = {}
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
});
//每個對象執行個體都有toString方法
core_toString = class2type.toString
//主方法
type: function( obj ) {
if ( obj == null ) {
return String( obj );
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[ core_toString.call(obj) ] || "object" :
typeof obj;
}
解讀:
1、class2type生成後的内容為
var class2type = {
"[object Boolean]":"boolean",
"[object Number]":"number",
"[object String]":"string",
"[object Function]":"function",
"[object Array]":"array",
"[object Date]":"date",
"[object RegExp]":"regexp",
"[object Object]":"object",
"[object Error]":"error"
2、core_toString使用的是對象執行個體的toString
所有繼随自Object的對象都有toString方法,為什麼一定要使用object.toString,因為array,function雖然有toString方法,但該方法進行了重寫,array調用toString列印的數組成員用逗号隔開的字元串。這裡使用的是{}.toString.call(obj);改變toString的this指向為object執行個體。jquery為什麼使用的是class2type.toString.call,這樣就可以少聲明一個object。
var func = function(){};
var arr = [];
console.log({}.toString.call(func)); //[object Function]
console.log({}.toString.call(arr)); //[object Array]
這樣就得到class2type的鍵名,以此判斷資料類型。
二、$.each() 周遊一個數組或對象。
each()其實還是使用的for來進行循環的,除了友善外,因其做了一下簡單的封裝,是以效率還是要比for差,對于大型循環,盡量使用for.
三、$.trim() 去除字元串兩端的空格。
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
core_version = "1.9.1"
//僅僅是使用字元串的trim方法
core_trim = core_version.trim
//主方法,首先嘗試使用字元串原生的trim方法(非IE支援)
//不支援的話,使用String.prototype.trim.call("\uFEFF\xA0")
//最後使用正則replace
trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
function( text ) {
return text == null ?
"" :
core_trim.call( text );
} :
// 上述兩個方法不支援,使用自定義的方法,清空兩邊的空格或特殊字元
( text + "" ).replace( rtrim, "" );
該方法需要解釋的是,“\uFEFF”和“\xA0”。
某些軟體,在儲存一個以UTF-8編碼的檔案時,會在檔案開始的地方插入三個不可見的字元(0xEF 0xBB 0xBF,即BOM),轉碼後是“\uFEFF”,是以我們在讀取時需要自己去掉這些字元。
“\xA0”其實就是HTML中常見的“ ”
四、$.isNumeric() 判斷是否是數字
isNumeric: function( obj ) {
return !isNaN( parseFloat(obj) ) && isFinite( obj );
isFinite() 函數用于檢查其參數是否是無窮大。如果 number 是有限數字(或可轉換為有限數字),那麼傳回 true。否則,如果 number 是 NaN(非數字),或者是正、負無窮大的數,則傳回 false。
五、$.isEmptyObject() 判斷對象是否為空
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
return true;
這個方法很好懂,就不多解釋
六、$.parseJSON() 将JSON字元串轉換為JSON對象
// JSON RegExp
rvalidchars = /^[\],:{}\s]*$/,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g
parseJSON: function( data ) {
// 如果有原生的JSON對象支援,使用原生對象
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
if ( data === null ) {
return data;
if ( typeof data === "string" ) {
// 去掉兩端空格,制表符,bom
data = jQuery.trim( data );
if ( data ) {
// 保證輸入的字元串是可用的JSON字元串
if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
console.log(data);
return ( new Function( "return " + data ) )();
}
}
jQuery.error( "Invalid JSON: " + data );
這個方法主要是看上面幾個正規表達式,從字元串轉JSON對象,僅僅是使用return ( new Function( “return ” + data ) )();
七、$.globalEval() 在全局作用域執行一段JS腳本
// 在全局作用域執行JS腳本
globalEval: function( data ) {
if ( data && jQuery.trim( data ) ) {
// 在IE中使用execScript
// 因為使用匿名函數,是以作用域使用的是window
( window.execScript || function( data ) {
window[ "eval" ].call( window, data );
} )( data );
jQuery該方法源于:Jim Driscoll
方法原理:eval作用域問題
var a = "window";
function b(){
eval('var a = "b"');
b();
alert(a); //a的結果為window;IE、chrome、FF結果一緻
window.eval和eval不一樣的地方:
window.eval('var a = "b"');
alert(a); //IE下還是a的結果還是window,chrome、FF的a的結果b