jQuery的主體如下:
(function(){ ……})();
對於Javascript基礎不太好好的人來說比較奇怪。實際上,這個表達式聲明了一個匿名函數(第一個括號),然後再執行它(第二個括號)。在這個函數中,完成了jQuery一系列方法和對象的定義。第24行很關鍵,
代碼如下:
jQuery = window.jQuery = window.$ = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
}
在這裡,定義了十分強大的$函數。$其實是jQuery的一個別名。jQuery才是“正宗”的jQuery函數,$的定義只是為了減少程序員的打字量。$很容易和其他庫沖突,例如著名的prototype庫也使用了這個名字。不過jQuery和其他庫沖突的機會就少多了,因此使用jQuery 要比$安全的多。下面再說沖突的問題。再看return的對象fn的定義,第35行
代碼如下:
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) { …… }, ……
};
很顯然fn只是一個jQuery的原型的簡寫而已。其中定義了一個init函數。實際上,init充當的是jQuery的構造函數的角色。當我們使用var i=$(‘selector')這樣的代碼的時候,可以發現變量i被jQuery包裹起來了,也就是i帶上了jQuery.fn的方法。很明顯,i的prototype被指向了jQuery.fn。再Javascript的世界裡,可以說,i是jQuery的一個實例,你嘗試下 i instanceof jQuery,返回的是true。然而,這裡並沒有用 i=new $(selector); 我估計,$是如此常用的一個函數,如果每次都要使用new來構造一個對象的話,那也太麻煩了,這就是init存在的理由,$本身被定義為一個很簡單的函數,它內部僅有一行代碼,返回一個init對象。我們每調用一次$(selector)方法,都返回一個jQuery對象。有點工廠模式的味道。當然,如果你對Javascript比較熟悉,就會知道這樣是不夠的,我們需要把init的prototype設為jQuery.fn,代碼541行:
jQuery.fn.init.prototype = jQuery.fn;
到540行為止,都是定義的jQuery的原型對象,用OO語言的話說,相當於實例方法,從540行開始,定義了一系列jQuery的方法,相當於靜態方法。至此,拋開方法的具體實現不談(有些實在是太困難了),jQuery的結構基本上是明了的了。下面開始介紹擴展。
擴展jQuery首先要注意的就是避免命名沖突,尤其是搶手的$。考慮周到的jQuery設計了一個jQuery.noConflict()方法,使得jQuery可以拱手讓出$符號,避免和其他庫沖突,而程序員可以使用完整的符號jQuery來調用jQuery提供的方法。noConflict()的實現簡單而巧妙,順便看一下,首先在第21行,
// Map over the $ in case of overwrite
_$ = window.$,jQuery首先記錄下windows.$,注意這行代碼的運行時間非常早,在jQuery任何函數執行之前就會被執行。當然,這裡的_$也有沖突的可能,不過概率是在是太小了,誰會用這麼詭異的名字作為關鍵的變量呢。此時如果$已經被其他庫占用,它的值會保留在_$中,在任何時候,只要調用jQuery.noConflict方法,619行,其代碼如下:
代碼如下:
noConflict: function( deep ) {
window.$ = _$;
if ( deep )
window.jQuery = _jQuery;
return jQuery;
},
這樣,$就又還回去了。
作為插件開發者,我們無法保證$是否被拱手相讓,最保險的是調用jQuery方法,然而有一個技巧可以保留簡單的$而不影響其他部分,那就是:
代碼如下:
(function($){
// plugin code goes here, you can use $ safely.
})(jQuery);
關於插件的js文件的命名,一般是jquery.pluginname.js。
要擴展jQuery工具函數(靜態函數)是很容易的,下面一個例子實現一個將數字擴展成固定位數的字符串的函數。
代碼如下:
(function($) {
$.toFixedWidth = function(value, length, fill) {
var res = value.toString();
if (!fill) fill = 0;
var padding = length - res.length;
if (padding < 0) {
res = res.substr(-padding);
} else {
for (var n = 0; n < padding; n++)
res = fill + res;
}
return res;
}
})(jQuery);
要編寫包裝集的方法也同樣容易,下面實現一個使表單元素只讀的方法:
代碼如下:
$.fn.setReadOnly = function(readonly) {
return this.find('input:text').attr('readonly', readonly).css('opacity', readonly ? 0.5 : 1.0);
}
下面編寫一個小頁面測試下,這個頁面模擬的是訂單提交頁面,如果用戶需要發票,需要填寫發票信息,否則不能填寫發票信息。
代碼如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jQuery Extension</title>
<script src="jquery-1.3.2.js" type="text/javascript"></script>
<script src="jquery.yinzixin.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
$('#OrderID').val($.toFixedWidth('123', 8));
$('#InvoiceRequired').click(function() {
$('.InvoiceInfo').setReadOnly(!this.checked);
});
$('.InvoiceInfo').setReadOnly(false);
}
);
</script>
</head>
<body>
<form>
Order ID:<input type="text" id="OrderID" /> <br />
<input type="checkbox" id="InvoiceRequired" />Invoice Required<br />
<div class="InvoiceInfo">
Inovice Tilte:<input type="text" id="Text1" />
Invoice Content:<input type="text" id="Text2" />
</div>
<input type="button" value="Submit" />
</form>
</body>
</html>