(function($){})(jQuery)資料記錄


對於匿名函數大家應該比較熟悉,那么(function($){})(jQuery)就比較容易理解了. 就是寫了一個匿名函數同時理解傳遞JQuery實參調用.

等同於:

  

var fn = function($){....}; 
fn(jQuery); 

 

這樣的寫法經常出現在各種jQuery插件中,其關鍵原因在於: jQuery插件很多,你無法保證自己的定義和使用變量/函數名稱不會用於其它插件中,那么最好的辦法就是讓你自己的代碼具有"封裝性"那么局部變量和局部函數就是很好的解決辦法,也就是將所有內容寫入一個匿名函數中.

同時,由於基於jQuery的插件都要用到JQuery本身,就需要導入到匿名函數中.

說到這里就干脆將jQuery的關鍵點拿出來瞅瞅,若不是專業前端工程師看看這部分重點也就ok了.

以下內容來源"

看了這個才發現jQuery源代碼不是那么晦澀

"

一些晦澀的操作符:

(function(){})();

幾乎所有的開源js代碼開篇都是這樣(function(……){……})(……);

下面是Jquery的部分源碼:

(function( window, undefined ) {
    var jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context );
    },

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

    // Map over the $ in case of overwrite
    _$ = window.$,
    ……
    indexOf = Array.prototype.indexOf;

    // Expose jQuery to the global object
    window.jQuery = window.$ = jQuery;
})(window);

那么這個操作符(function(){})();到底是什么意思呢?

(function(){})中的定義了一個function,緊接着的()表示立即執行這個function

我們看到Jquery源碼第一個()中是定義了一個匿名function( window, undefined ) {};接着末尾有個(window),就表示執行這個匿名function,並傳入參數window

在匿名function( window, undefined ) {}中,定義了一個局部變量jQuery;然后在末尾我們看到Jquery末尾有一句window.jQuery = window.$ = jQuery; 這句代碼就表示,將此前定義的jQuery導出到window對象。這也是為什么我們可以在代碼任何地方直接使用$ 、jQuery 對象,因為在這里已經將$ 、jQuery 對象掛載到window下去了,而window.$ 、window.jQuery 與直接使用$ 、jQuery 是沒有區別的。

(注意,這個window對象是傳入的參數window,而不是瀏覽器window對象!!一個形參、一個實參。我們可以在定義function的時候,將參數window取名為其他字符。所以我們看到jquery.min.js中這個匿名function變成了(function(E,B){})(window);)

通常(function(){})()用來封裝一些私有成員或者公共成員的導出。

令人迷惑的","

我們知道 , 一般用於一次定義多個變量、定義多個參數等。像上面的jQuery源碼中在var jQuery后面,使用,一次定義了很多個變量。 但是,像下面的代碼,可能大家就不一定看得懂了:

//html:<input type="hidden" value="king" id="nameHide"/>
jQuery(document).ready(function() {
    var showName=function(){
        var value,nameInput=$("#nameHide");
        return nameInput.show(),value=nameInput.val();
    };
    alert(showName());
});
//結果:彈出king

這里的nameInput.show(),value=nameInput.val()中的,運算符的作用是返回,右側表達式的值。所以,return 后面如果有多個表達式,且表達式之間由,隔開,整個return表達式返回的是最后一個,右側的表達式的值。

,在開源代碼中常常被用於return表達式中,以及跟下面我們要講到的()運算符一起使用。

()廣義上的代碼包裝

我們遇到復雜的邏輯表達式時,我們通常會把需要一起運算的表達式用“()”包起來:(a||b)&&(c||d)

其實,我們可以這樣理解:()運算符將一個表達式包裹起來作為一個整體進行運算,然后返回這個整體的值。

那么上面的(function(){})()中左側定義function的()也是這個作用,將這個function給包裹起來,然后返回這個function。我們調用方法一般是a();那么(function(){})的作用就是返回這個function對象,然后(function(){})()右側的()表示調用這個function

我們再來看其他的用法:

 

//html:<input value="kings" id="name"/><div id="nameErrorTip">輸入錯誤!</div>
jQuery(document).ready(function() {
    var nameValidate=function(){
        var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip"); 
        return (value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"對了,輸入為king!"):(nameErrorTip.show(),"請輸入king!");
    };
    alert(nameValidate());
});

//結果 nameErrorTip顯示,彈出"請輸入king!"
//html:<input value="king" id="name"/><div id="nameErrorTip">輸入錯誤!</div>
//結果 nameErrorTip隱藏,彈出"對了,輸入為king!"

這里(value=nameInput.val(),value=="king")()將里面的表達式作為一個整體進行運算,而里面的表達式又是由,構成的多個表達式組,所以執行的時候會把這多個表達式都執行一次,並且返回最后一個表達式的值!

所以 (value=nameInput.val(),value=="king")執行時,先運算value的值,再判斷是否為"king"。如果為king,會執行(nameErrorTip.hide(),"對了,輸入為king!")。這個表達式又先將nameErrorTip隱藏,再返回一個"對了,輸入為king!"字符串作為 整個return的值。

||、&&、if()邏輯讓人頭暈

||&&兩側參與運算的是邏輯表達式,if()中也是。但是我們在很多開源代碼中看到的||&&參與運算的表達式看起來卻好像不是邏輯表達式……

下面節選一段jQuery.tool中的一段源碼:

e.circular || (f.onBeforeSeek(function(a, b) {
    setTimeout(function() {
        a.isDefaultPrevented()||(
            n.toggleClass(
                e.disabledClass,
                b <= 0
            ),
            o.toggleClass(
                e.disabledClass,
                b >= f.getSize() - 1
            )
        )
    }, 1)
}),
e.initialIndex || n.addClass(e.disabledClass)),
f.getSize() < 2 && n.add(o).addClass(e.disabledClass),
e.mousewheel && a.fn.mousewheel && b.mousewheel(function(a, b) {
    if (e.mousewheel) {
        f.move(b < 0 ? 1 : -1, e.wheelSpeed || 50);
        return !1
    }
});

這里有多處||&&。但與運算的表達式卻是調用某個函數的返回值。

其實,js中的邏輯表達式是按照真值、假值來分的。true是真值;1是真值;一個對象也是真值;false是假值;""0是假值。

在js中&&||不一定都是用來判斷一個表達式的邏輯值是truefalse,更多的是用來依據真值或者假值執行相應操作!

我們知道,||運算的時候,會先運算左側的表達式的值,如果為真值,那么真個表達式就為真值,而同時右側表達式是真值、假值都不重要,因為右側表達式都不再繼續參與運算了。又如果左側為假值,則繼續運算右側表達式。

&&則先運算左側表達式,兩側表達式,一個為假值,則整個表達式為假值。

這里關鍵是這個真值或者假值的運算過程中,我們可以使用上面介紹的,()將一組表達式串起來執行。也就是說,這個表達式可能會很長很長,我甚至可以定義一個function在里面。這些表達式在執行過程中,有可以進行某些附加操作。比如我們希望這個表達式為真值的時候我們做什么,假值的時候做什么,把這些操作用(),串起來作為一個整體運算。

於是就有了上面的復雜代碼。

另外:

if(a){
    b
}

可簡寫為a&&(b); b可以是一個function調用表達式,或者是多個語句用","串起來。但前提是a已定義,否則會報錯。

我們來看個實例吧。是上面例子的升級版。我們加入一個nameInput是否存在的判斷:

jQuery(document).ready(function() {
    var nameValidate=function(){
        var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip"),msg;
        msg=(value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"對了,輸入為king!"):(nameErrorTip.show(),"請輸入king!");
        return (nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg)||"沒有找到name輸入框或者輸入框沒有值!";
    };
    alert(nameValidate());
});

測試:

//html:<input value="king" id="myName"/>
//結果:彈出“沒有找到name輸入框或者輸入框沒有值!”

//<input value="king" id="name"/><div id="nameErrorTip">輸入錯誤!</div>
//結果:彈出“對了,輸入為king!”,nameErrorTip被隱藏

return表示中 nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg會先運算 nameInput.length的值,如果length0則表達式為假值,如果為1則為真值。val()操作也是如此,如果val()結果為""則表達式也是假值。幾個表達式之間為&&運算,則表示依次運算幾個表達式的值,如果都未真值則返回最后一個表達式的值,由於整個表達式與 "沒有找到name輸入框或者輸入框沒有值!" 表達式之間是||運算,所以前面的表達式其中一個表達式為假值則返回||右側的表達式的值,也就是整個“沒有找到name輸入框或者輸入框沒有值!”字符串。

說到這里,我之前寫過一篇文章專門說到了&&||的真值、假值問題。有興趣的可以去看看。

談了這些難以理解的運算符后,大家可能會覺得,這個javascript為什么要搞這些晦澀的運算符呢?

我的理解是因為javascript通常在客戶端運行,那么從服務器端將js代碼傳輸到客戶端肯定需要耗時。上面的這些運算符都是為了減少代碼量。再加上使用壓縮工具去掉空格,替換變量名,就可以使用壓縮率達到最好。

再這里,我也告訴大家,其實我也非常反對在實際應用中采用這種寫法的,因為會對初學者造成閱讀障礙。我寫這篇文章的目的不是為了讓大家以后就這樣用,而是告訴大家可以這樣用,在一些開源代碼中遇到了能看懂。不可為了炫耀而故意寫一些晦澀的代碼。

最后,為了幫助我們更快的找到變量定義、理清代碼整體結構,給大家推薦一個eclipse的js插件:Spket,支持jQuery代碼提示哦!

來源:http://www.tashan10.com/

暮成雪 博客


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM