天天看點

jQuery源碼解讀:部份jQuery工具方法實作

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中常見的“&nbsp”

四、$.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

繼續閱讀