1. 程式人生 > >jquery原始碼解析日常

jquery原始碼解析日常

介紹:JQuery是繼prototype之後又一個優秀的Javascript庫。它是輕量級的js庫 ,它相容CSS3,還相容各種瀏覽器(IE 6.0+, FF1.5+, Safari 2.0+, Opera 9.0+),jQuery2.0及後續版本將不再支援IE6/7/8瀏覽器。jQuery使使用者能更方便地處理HTML、events、實現動畫效果,並且方便地為網站提供AJAX互動。jQuery還有一個比較大的優勢是,它的文件說明很全,而且各種應用也說得很詳細,同時還有許多成熟的外掛可供選擇。jQuery能夠使使用者的html頁面保持程式碼和html內容分離,也就是說,不用再在html裡面插入一堆js來呼叫命令了,只需要定義id即可。

jQuery是一個相容多

瀏覽器的javascript庫,核心理念是write less,do more(寫得更少,做得更多)。
jQuery是免費、開源的,使用MIT許可協議。jQuery的語法設計可以使開發更加便捷,例如操作文件物件、選擇DOM元素、製作動畫效果、事件處理、使用Ajax以及其他功能。除此以外,jQuery提供API讓開發者編寫外掛。其模組化的使用方式使開發者可以很輕鬆的開發出功能強大的靜態或動態網頁

1.$.each函式 原生js實現 

 var gt={
        each:function (object,callback)
        {
            var type=(function () {
               //分為不同的幾個型別
                switch (object.constructor){
                    case Object:
                        return 'Object';
                        break;
                    case Array:
                        return 'Array';
                        break;
                    case NodeList:
                        return 'NodeList';
                        break;
                    case HTMLCollection:
                        return 'HTMLCollection'
                    default:
                        return 'null';
                        break;
                }
            })()
            //為陣列或者類陣列 的情況下
            if(type==="Array" || type==='NodeList' || type==='HTMLCollection'){
                //由於存在類陣列的nodelist和HTMLCollection,所以不能直接呼叫every方法
                //every() 方法用於檢測陣列所有元素是否都符合指定條件(使用指定函式檢測陣列中的所有元素)。
                //如果陣列中檢測到有一個元素不滿足,則整個表示式返回 false ,且剩餘的元素不會再進行檢測,當且僅當所有元素都滿足條件,則返回 true。
                //注意: every() 不會對空陣列進行檢測,不會改變原始陣列。
                //用法 array.every(function(currentValue,index,arr), thisValue)
                /*
                * function(currentValue, index,arr)	必須。函式,陣列中的每個元素都會執行這個函式
                        函式引數:
                        引數	描述
                        currentValue	必須。當前元素的值
                        index	可選。當前元素的索引值
                        arr	可選。當前元素屬於的陣列物件
                        thisValue	可選。物件作為該執行回撥時使用,傳遞給函式,用作 "this" 的值。
                        如果省略了 thisValue ,"this" 的值為 "undefined"
                */
                [].every.call(object,function (v,i) {
                    return callback.call(v,i,v) === false?false:true;
                })
            //為物件的情況下
            }else if(type==="Object"){
                for(var i in object){
                    if(callback.call(object[i],i,object[i])===false){
                        break;
                    }
                }
            }
        }
    }            

  呼叫執行

   //陣列呼叫
    gt.each([1,2,3,4],function (i, v) {
        console.log(v)
    })
    //物件呼叫
    gt.each([{name:"GT",age:10},{name:"Alice",age:11},{name:"Mike",age:12},{name:"Joe",age:13}],function (i, v) {
        console.log(v.name +'今天'+v.age+'歲了')
    })
    //元素集呼叫  兩種元素集型別
    var ele=document.getElementsByClassName('eachListLi')  //HTMLCollection
    var ele2= document.querySelectorAll('.eachListLi'); //NodeList
    gt.each(ele,function (i, v) {
        console.log(v)
    })
    gt.each(ele2,function (i, v) {
        console.log(i+':'+v)
    })

   執行結果:

      對於兩個js方法的解釋:

    (1)   every方法   如果陣列中檢測到有一個元素不滿足,則整個表示式返回 false ,且剩餘的元素不會再進行檢測 當且僅當 所有元素都滿足條件的時候 返回true

   

    (2)  call方法    

    call 和 apply 兩個方法的第一個實參 是要呼叫函式的母物件 ,他是呼叫上下文 ,在函式提內通過this的來獲取對他的引用。要想以物件 o的方法 來呼叫函式f(),可以這樣使用call 和apply

  f.call(o)
    f.apply(o)
    //上面兩個實現功能和下面的類似  假設o物件中不存在m方法
    o.m=f;//將f儲存為o的臨時方法
    o.m();//執行方法 不傳引數
    delete o.m //刪除臨時方法

  在es5嚴格模式中,call 和apply 的第一個實參會變成this的值,哪怕傳入的實參的原始值是null 或者undefined ,在非嚴格模式中,傳入的null和undefined 會被全域性物件代替 ,而其他原始值則會被相應的包裝物件代替

在看 jq是如何實現的

 //jq定義的each方法 
        each: function( obj, callback ) {
            var length, i = 0;
            //分為兩個陣列型別 和物件型別 分別執行方法
            //類陣列型別
            if ( isArrayLike( obj ) ) {
                length = obj.length;
                for ( ; i < length; i++ ) {
                    if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
                        break;
                    }
                }
            } else {
                //物件型別
                for ( i in obj ) {
                    if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
                        break;
                    }
                }
            }

            return obj;
        },

  檢驗是否為類陣列的方法

 //類陣列
    function isArrayLike( obj ) {

        // Support: real iOS 8.2 only (not reproducible in simulator)
        // `in` check used to prevent JIT error (gh-2145)
        // hasOwn isn't used here due to false negatives
        // regarding Nodelist length in IE
        //支援:僅限真正的iOS 8.2(在模擬器中不可重現)
        //`in`檢查用於防止JIT錯誤(gh-2145)
        // 此處未使用hasOwn
        //關於IE中的Nodelist長度  這一點不知道會有什麼影響 可能是為了相容
        var length = !!obj && "length" in obj && obj.length,
                type = toType( obj );
        //當物件 是 方法和window物件的時候 直接 返回false
        if ( isFunction( obj ) || isWindow( obj ) ) {
            return false;
        }
        //只有 1.型別為陣列 2.長度為0 3.為數字型別 且長度大於1  ( length - 1 ) in obj的情況下 返回ture
        return type === "array" || length === 0 ||
                typeof length === "number" && length > 0 && ( length - 1 ) in obj;
    }

  初步判斷型別的方法 聲明瞭兩個變數 

var class2type = {};

var toString = class2type.toString;

 toType的方法

//toType的方法  初步判斷型別的方法
    function toType( obj ) {
        //當obj為null 是 返回null 型別字串
        if ( obj == null ) {
            return obj + "";
        }

        // Support: Android <=2.3 only (functionish RegExp)
        //支援:Android <= 2.3(功能RegExp)
        //當為 物件和方法的時候 取class2type物件中的toString.call( obj )               這一塊沒看懂
//或者直接返回object型別 當不為物件 方法 null的情況下 使用typeof 判斷後返回型別 return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj; }

  總結 $.each的方法實現 首先要 分開型別 陣列 和物件 然後 陣列用for 迴圈 物件用 for in 迴圈完成