學會讀JQuery等JS插件源碼

不少人以爲jquery、ext等一些開源js源代碼 十分的晦澀,讀不懂,遇到問題須要調試也很費勁。其實我我的感受主要是有幾個方面的緣由:javascript

一、對一些js不經常使用的語法、操做符不熟悉html

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

三、js中容許變量先使用後定義,會形成咱們看代碼時候突然冒出來一個變量、function,卻找不到是在哪裏定義的。jquery

 

那麼今天給你們分享一下個人經驗,掃清你的障礙。瀏覽器

1、一些晦澀的操做符:服務器

一、(function(){})();app

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

下面是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(){})()用來封裝一些私有成員或者公共成員的導出。

 

二、使人迷惑的","

咱們知道「,」通常用於一次定義多個變量、定義多個參數等。像上面的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表達式中,以及跟下面咱們要講到的"()"運算符一塊兒使用。

 

三、「()」廣義上的代碼包裝

咱們遇到複雜的邏輯表達式時,咱們一般會把須要一塊兒運算的表達式用「()」包起來:(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的值。

 

四、||、&&、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在裏面。這些表達式在執行過程當中,有能夠進行某些附加操做。好比咱們但願這個表達式爲真值的時候咱們作什麼,假值的時候作什麼,把這些操做用"()"、","串起來做爲一個總體運算。

因而就有了上面的複雜代碼。

 

咱們來看個實例吧。是上面例子的升級版。咱們加入一個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輸入框或者輸入框沒有值!」字符串。

 

這個javascript爲何要搞這些晦澀的運算符呢?

由於javascript一般在客戶端運行,那麼從服務器端將js代碼傳輸到客戶端確定須要耗時。上面的這些運算符都是爲了減小代碼量。再加上使用壓縮工具去掉空格,替換變量名,就可使用壓縮率達到最好。

相關文章
相關標籤/搜索