看了這個才發現jQuery原始碼不是那麼晦澀

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   os   ar   使用   java   

看了這個才發現jQuery原始碼不是那麼晦澀

很多人覺得jquery、ext等一些開源js原始碼 十分的晦澀,讀不懂,遇到問題需要調試也很費勁。其實我個人感覺主要是有幾個方面的原因:

1、對一些js不常用的文法、操作符不熟悉

2、某個function中又嵌套了一些內部的function,使得整個代碼的階層不像java代碼那麼清晰。

3、js中允許變數先使用後定義,會造成我們看代碼時候忽然冒出來一個變數、function,卻找不到是在哪裡定義的。

 

那麼今天給大家分享一下我的經驗,掃清你的障礙。

一、一些晦澀的操作符:

1、(function(){})();

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

下面是Jquery的部分源碼:

 

Js代碼  
  1. (function( window, undefined ) {  
  2.     var jQuery = function( selector, context ) {  
  3.         // The jQuery object is actually just the init constructor ‘enhanced‘  
  4.         return new jQuery.fn.init( selector, context );  
  5.     },  
  6.   
  7.     // Map over jQuery in case of overwrite  
  8.     _jQuery = window.jQuery,  
  9.   
  10.     // Map over the $ in case of overwrite  
  11.     _$ = window.$,  
  12.     ……  
  13.     indexOf = Array.prototype.indexOf;  
  14.   
  15.     // Expose jQuery to the global object  
  16.     window.jQuery = window.$ = jQuery;  
  17. })(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(){})()用來封裝一些私人成員或者公用成員的匯出。

 

2、令人迷惑的","

我們知道“,”一般用於一次定義多個變數、定義多個參數等。像上面的jQuery源碼中在var jQuery後面,使用“,”一次定義了很多個變數。

但是,像下面的代碼,可能大家就不一定看得懂了:

 

Js代碼  
  1. //html:<input type="hidden" value="king" id="nameHide"/>  
  2. jQuery(document).ready(function() {  
  3.     var showName=function(){  
  4.         var value,nameInput=$("#nameHide");  
  5.         return nameInput.show(),value=nameInput.val();  
  6.     };  
  7.     alert(showName());  
  8. });  
  9. //結果:彈出king  

 這裡的“nameInput.show(),value=nameInput.val()”中的“,”運算子的作用是返回","右側運算式的值。 所以,return 後面如果有多個運算式,且運算式之間由","隔開,整個return運算式返回的是最後一個","右側的運算式的值。

 

“,”在開原始碼中常常被用於return運算式中,以及跟下面我們要講到的"()"運算子一起使用。

 

3、“()”廣義上的程式碼封裝裝

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

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

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

 

我們再來看其他的用法:

 

 

Js代碼  
  1. //html:<input value="kings" id="name"/><div id="nameErrorTip">輸入錯誤!</div>  
  2. jQuery(document).ready(function() {  
  3.     var nameValidate=function(){  
  4.         var value,nameInput=$("#name"),nameErrorTip=$("#nameErrorTip");   
  5.         return (value=nameInput.val(),value=="king")?(nameErrorTip.hide(),"對了,輸入為king!"):(nameErrorTip.show(),"請輸入king!");  
  6.     };  
  7.     alert(nameValidate());  
  8. });  
  9.   
  10. //結果 nameErrorTip顯示,彈出"請輸入king!"  
  11.   
  12.   
  13.   
  14. //html:<input value="king" id="name"/><div id="nameErrorTip">輸入錯誤!</div>  
  15. //結果 nameErrorTip隱藏,彈出"對了,輸入為king!"  

 

 

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

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

 

 

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

 

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

 

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

 

Js代碼  
  1. e.circular || (f.onBeforeSeek(function(a, b) {  
  2.                     setTimeout(function() {  
  3.                                 a.isDefaultPrevented()  
  4.                                         || (n.toggleClass(e.disabledClass,  
  5.                                                 b <= 0), o.toggleClass(  
  6.                                                 e.disabledClass, b >= f  
  7.                                                         .getSize()  
  8.                                                         - 1))  
  9.                             }, 1)  
  10.                 }), e.initialIndex || n.addClass(e.disabledClass)), f.getSize() < 2  
  11.                 && n.add(o).addClass(e.disabledClass), e.mousewheel  
  12.                 && a.fn.mousewheel && b.mousewheel(function(a, b) {  
  13.                             if (e.mousewheel) {  
  14.                                 f.move(b < 0 ? 1 : -1, e.wheelSpeed || 50);  
  15.                                 return !1  
  16.                             }  
  17.                         });  

 

 這裡有多處||、&&。但與運算的運算式卻是調用某個函數的傳回值。

 

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

 

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

 

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

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

 

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

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

 

另外,大家注意:下面的寫法是等價的:

 

Js代碼  
  1. if(a){  
  2.     b  
  3. }  
  4. //等價於  
  5. a&&(b)  
  6. //b可以是一個function調用運算式,或者是多個語句用","串起來  

 

 

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

 

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

 

測試:

 

Js代碼  
  1. //html:<input value="king" id="myName"/>  
  2. //結果:彈出“沒有找到name輸入框或者輸入框沒有值!”  
  3.   
  4. //<input value="king" id="name"/><div id="nameErrorTip">輸入錯誤!</div>  
  5. //結果:彈出“對了,輸入為king!”,nameErrorTip被隱藏  

 

 

return表示 中 nameInput.length&&nameInput.val()&&nameErrorTip.length&&msg 會先運算 nameInput.length的值,如果length為0則運算式為假值,如果為1則為真值。val()操作也是如此,如果val()結果 為""則運算式也是假值。幾個運算式之間為&&運算,則表示依次運算幾個運算式的值,如果都未真值則返回最後一個運算式的值,由於整個運算式與

"沒有找到name輸入框或者輸入框沒有值!"

運算式之間是||運算,所以前面的運算式其中一個運算式為假值則返回||右側的運算式的值,也就是整個“沒有找到name輸入框或者輸入框沒有值!”字串。

 

說到這裡,我之前寫過一篇文章專門說到了&&、||的真值、假值問題。有興趣的可以去看看。http://my249645546.iteye.com/blog/1553202

 

 

 

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

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

 

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

 

最後,為了協助我們更快的找到變數定義、理清代碼整體結構,給大家推薦一個eclipse的js外掛程式:Spket,支援jQuery代碼提示哦!

看了這個才發現jQuery原始碼不是那麼晦澀

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.