談談 jQuery 中的防衝突(noConflict)機制

淘寶UED發表於2013-03-12

  許多的 JS 框架類庫都選擇使用 $ 符號作為函式或變數名,jQuery 是其中最為典型的一個。在 jQuery 中,$ 符號只是 window.jQuery 物件的一個引用,因此即使 $ 被刪除,window.jQuery 依然是保證整個類庫完整性的堅強後盾。jQuery 的 API 設計充分考慮了多框架之間的引用衝突,我們可以使用 jQuery.noConflict 方法來輕鬆實現控制權的移交。

  jQuery.noConflict 方法包含一個可選的布林引數[1],用以決定移交 $ 引用的同時是否移交 jQuery 物件本身:

  jQuery.noConflict([removeAll])

  預設情況下,執行 noConflict 會將變數 $ 的控制權移交給第一個產生 $ 的庫;當 removeAll 設定為 true 時,執行 noConflict 則會將 $ 和 jQuery 物件本身的控制權全部移交給第一個產生他們的庫。

  例如在 KISSY 和 jQuery 混用,並且慣用 $ = KISSY 來簡化 API 操作的時候,就能夠通過這個方法解決命名衝突的問題。

  那麼這個機制是如何實現的呢?閱讀 jQuery 原始碼開頭[2],首先做的一件事情是這樣的:

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

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

  容易理解的是,jQuery 通過兩個私有變數對映了 window 環境下的 jQuery 和 $ 兩個物件,以防止變數被強行覆蓋。一旦 noConflict 方法被呼叫,則通過 _jQuery, _$, jQuery, $ 四者之間的差異,來決定控制權的移交方式,具體的程式碼如下:

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

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

                return jQuery;
        }

  再來看上面所說的引數設定問題,如果 deep 沒有設定,_$ 覆蓋 window.$,此時 jQuery 別名 $ 失效,但 jQuery 本身完好無損。如果有其他類庫或程式碼重新定義了 $ 變數,它的控制權就完全交接出去了。反之如果 deep 設定為 true 的話,_jQuery 覆蓋 window.jQuery,此時 $ 和 jQuery 都將失效。

  這種操作的好處是,不管是框架混用還是 jQuery 多版本共存這種高度衝突的執行環境,由於 noConflict 方法提供的移交機制,以及本身返回未被覆蓋的 jQuery 物件,完全能夠通過變數對映的方式解決衝突。

  但無法避免的事實是可能導致的外掛失效等問題,當然通過簡單修改上下文引數即可恢復 $ 別名:

var query = jQuery.noConflict(true);
(function ($) {

     // 外掛或其他形式的程式碼,也可以將引數設為 jQuery

})(query);

  [1] http://api.jquery.com/jQuery.noConflict/#jQuery-noConflict-removeAll
  [2] https://github.com/jquery/jquery/blob/master/src/core.js

相關文章