Jquery中文網 伊蒂哈德7比2 www.jvkwgx.com.cn
Jquery中文網 >  jQuery  >  jquery 教程  >  正文 從jQuery學到的幾件事情

伊蒂哈德vs塔什干火车头:從jQuery學到的幾件事情

發布時間:2016-09-18   編輯:伊蒂哈德7比2 www.jvkwgx.com.cn
jquery中文網為您提供從jQuery學到的幾件事情等資源,歡迎您收藏本站,我們將為您提供最新的從jQuery學到的幾件事情資源

伊蒂哈德7比2 www.jvkwgx.com.cn 最近想看一下jquery源碼,搜到了這樣一篇博客《從jQuery源碼學到的10件事情》
//www.paulirish.com/2010/10-things-i-learned-from-the-jquery-source/

本文基于這篇視頻博客,提煉了一些內容,分享給大家。

說明:
這篇文章寫于2010年,作者在視頻里使用的是jQuery 1.4版本,我根據視頻里講到的內容,對應目前的1字頭1.11版本做了一些調整,一些被拋棄或者被移除的內容頁做了刪減,并在此感謝原作者https://github.com/paulirish

黑箱/Black box

黑箱系統的概念是給定輸入返回輸出的一個系統,黑箱把實現過程進行封裝。這里說的jQuery黑箱是為js全局變量window輸出jQuery 和 $,而過程被封裝到黑箱里,與外界互不干擾。

jQuery 1.4版本的黑箱是利用了類似如下的自執行函數

(function( window, undefined){})(window)

作者給了一個比較通用的實現黑箱的方法

undefined = true;

(function(window, document, undefined){    
    if(foo == undefined) {
        }
})(this, document)

jQuery的黑箱里多傳了第三個形參叫做undefined,而傳實參的時候并沒有傳值,js里沒有傳值的形參會被設置為undefined,保證了黑箱內部undefined的正確性。js中,undefined作為一個全局屬性,是可以被賦值的,比如上述代碼中的undefined = true;

以自執行函數的模式實現黑箱的另外一個好處是利于壓縮,比如下述的情況,我們只需要在黑箱內部使用簡單的變量。

(function(A, B, C)){
    B.getElementById('')
})(this, document)

作者為匿名函數自執行舉了很多例子,比如下面這個,為頁面的某一部分不停地更新(以及不斷地執行)

(function loop(){
    doStuff();

    $('#update').load('awesomething.php',function(){
        loop();
    })
    //setTimeout(loop, 100)
})()

jQuery 1.11版本的黑箱采用了全新的工廠方法,本文不探究

noConflict的實現

這個函數的差異不大,1.11 版本代碼如下

var
    // Map over jQuery in case of overwrite
    _jQuery = window.jQuery,

    // Map over the $ in case of overwrite
    _$ = window.$;

jQuery.noConflict = function( deep ) {
    if ( window.$ === jQuery ) {
        window.$ = _$;
    }

    if ( deep && window.jQuery === jQuery ) {
        window.jQuery = _jQuery;
    }

    return jQuery;
};

我們可以看到防沖突的實現是先把之前的JQuery 和 $ 存起來,noConflict被調用的時候,再還給它們

與原生js屬性命名的轉換

1.4版本用的是props對象來存放jquery對屬性操作與原生js屬性操作的對應關系
1.11版縮減版本是這樣的

jQuery.extend({
    propFix: {
        "for": "htmlFor",
        "class": "className"
    },

    prop: function( elem, name, value ) {
        //...
        name = jQuery.propFix[ name ] || name;
    },

    propHooks: {
        //...
    }
});

jQuery.each([
    "tabIndex",
    "readOnly",
    "maxLength",
    "cellSpacing",
    "cellPadding",
    "rowSpan",
    "colSpan",
    "useMap",
    "frameBorder",
    "contentEditable"
], function() {
    jQuery.propFix[ this.toLowerCase() ] = this;
});

propFix 這個對象是存放對應關系表的,比如class轉換成className,prop函數負責處理這個關系表。
而下面的each很有意思,遍歷數組中那些屬性,然后把他們小寫格式對應到自己,放到 propFix

特效Speed

我們知道在jQuery里一些動畫我們可以直接通過normal,fast,slow 來定義實現速度,這個在源碼里是這樣定義的

jQuery.fx.speeds = {
    slow: 600,
    fast: 200,
    // Default speed
    _default: 400
};

調皮的原作者做了這樣一些事情:

var isIE 
//...

jQuery.fx.speeds._default = isIE ? 800 : 400
jQuery.fx.speeds.veryfast = 200;

$('...').fadeIn('veryfast')

一種是可以對default屬性做條件判斷,還有一種自定義速度,比如”veryfast”

.ready

ready函數 1.11版本和1.4版本有較大的差距,新版中很多東西我也不太能理解,我們就簡單的把核心拿出來看一下

jQuery.ready.promise = function( obj ) {
    //...省略若干
        } else if ( document.addEventListener ) {
            // 使用addEventListener "DOMContentLoaded" 監聽ready事件
            document.addEventListener( "DOMContentLoaded", completed, false );

            // 備選方案 "load"
            window.addEventListener( "load", completed, false );

        //如果IE
        } else {
            // Ensure firing before onload, maybe late but safe also for iframes
                        //IE下 attachEvent 的"onreadystatechange"
            document.attachEvent( "onreadystatechange", completed );

            // A fallback to window.onload, that will always work
                        //備選方案onload
            window.attachEvent( "onload", completed );

            // If IE and not a frame
            // continually check to see if the document is ready
            var top = false;

            try {
                top = window.frameElement == null && document.documentElement;
            } catch(e) {}

            if ( top && top.doScroll ) {
                (function doScrollCheck() {
                    if ( !jQuery.isReady ) {

                        try {
                            // Use the trick by Diego Perini
                            // //javascript.nwbox.com/IEContentLoaded/
                            top.doScroll("left");
                        } catch(e) {
                            return setTimeout( doScrollCheck, 50 );
                        }

                        // detach all dom ready events
                        detach();

                        // and execute any waiting functions
                        jQuery.ready();
                    }
                })();
            }
        }
    }
    return readyList.promise( obj );
};

.ready 利用了下面的.promise去做確保載入完成的工作,重點是
document.addEventListener( "DOMContentLoaded", completed, false );
window.addEventListener( "load", completed, false );
document.attachEvent( "onreadystatechange", completed );
window.attachEvent( "onload", completed );
兼容性考量的四種檢查方式

其中從top開始,做了一件事情就是IE下面,dom節點判斷是否有scroll,在IE下如果dom有scroll,沒有scroll到的元素對ready會有影響,這里面我的理解不夠,總之jQuery里用到了一個叫做Diego Perini的技巧,可以在注釋里的地址看到更多內容。

選擇器

$('#id').find('tag.thing') --- faster

$('#id tag.thing') ------- using sizzle

原作者在這里說了一個jquery效率的問題,上面的方法更快一些,而下面的方法稍微慢,簡單地說是因為下面的方法調用了sizzle,通過sizzle其實轉換成上述的模式,而id的調用則是直接過jQuery.init.

這里需要擴展一下,我們來看一下1.11里jQuery對象究竟長啥樣

jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        // Need init if jQuery is called (just allow error to be thrown if not included)
        return new jQuery.fn.init( selector, context );
}

jQuery對象其實是return了一個它自己的構造函數叫做init,我們再來看一下init做了些什么

// Initialize a jQuery object

    init = jQuery.fn.init = function( selector, context ) {
        var match, elem;

        // HANDLE: $(""), $(null), $(undefined), $(false)
            //超級省略...下略

        // Handle HTML strings

        // HANDLE: $(html) -> $(array)

        // HANDLE: $(html, props)

        // HANDLE: $(#id)

        // HANDLE: $(expr, $(...))

        // HANDLE: $(expr, context)

        // HANDLE: $(DOMElement)

        // HANDLE: $(function)


        return jQuery.makeArray( selector, this );
    };

// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;

從上面的摘取的代碼注釋中,我們可以看到jq自己的構造函數里處理了哪些情況,其中包括html標簽名和id的獲取,意味著這兩種獲取是最底層的,此外$()的其他處理都要經過其他的函數,效率上不如上述處理情況。
同時我們也能看到init的原型被賦予了jQuery.fn, 關于jQuery對象的相關內容,感興趣的朋友可以再多去了解一些。

jQ的狀態選擇符,比如:not,:has,:eq存放在
Sizzle.selectors.pseudos里面


您可能感興趣的文章:
初窺JQuery(二)事件機制(2)
jquery常用技巧及常用方法列表集合
jQuery的學習步驟
jQuery代碼優化 事件委托篇
jQuery 事件隊列調整方法
jquery 選擇器引擎sizzle淺析
JQuery優缺點分析說明
事件冒泡是什么如何用jquery阻止事件冒泡
JQuery優缺點分析說明
jQuery的運行機制和設計理念分析

[關閉]