一、jQuery函數
先回顧一下我們常用的jQuery格式,例如我們需要設置一個div的css樣式,那麼會寫成如下的格式:$(“#btn”).css()
,就有點類似於一個對象調用自己的方法,$(“#btn”)
是一個執行函數,在文檔的61行:
我們可以發現在63行,函數返回的是一個通過new創建的對象,這也是jQuery的巧妙之處,不通過new構造函來創建對象。這裏具體分析一下。
一般如果我們聽過構造函數來創建的話,會寫成如下格式:
function jquery(){} //創建構造函數
jquery.prototype.init = function() {}; // 原型初始化方法
jquery.prototype.css = function(){}; // 原型css方法
var JQ = new jquery(); //創建實例
JQ.init(); //調用初始化方法
JQ.css(); //調用css方法
這樣,我們就需要通過new來創建新的對象,如果我們將new操作寫在構造函數就可以達到類似於文檔中61到63行的作用。那麼返回的對象到底是什麼?
return new jQuery.fn.init( selector, context, rootjQuery );
這裏返回的是一個初始化構造的對象,那麼這個對象是怎麼與jQuery對象聯繫上的呢?在文檔的283行能找到關於jQuery.fn.init()
設置:
而關於jQuery.fn
的設置在96行能找到:
上面兩行指令可以等效爲如下:
jquery.prototype.init.prototype = jquery.prototype;
將一個對象的原型賦值給另外一個對象的原型,也就是原型的引用。這樣的話,改變jquery的原型也就等於改變了jquery.prototype.init的原型。也就是說在jQuery原型下定義方法,都可以在new出來的jQuery.fn.init()
下使用。
二、jQuery對象的屬性和方法
96~280行給jQuery對象增加一些原型屬性和方法,其屬性和方法簡化如下:
jQuery.fn = jQuery.prototype = {
jquery: 版本號;
constructor: 指定構造函數;
init(): 初始化以及管理參數,也就是選擇器的處理;
selector: 存儲選擇字符串;
length: this對象的長度;
toArray(): 轉數組;
get(): 轉原生集合;
pushStack(): JQ對象的入棧;
each(): 遍歷集合;
ready(): DOM加載的接口;
slice(): 集合的截取;
first(): 集合的第一項;
last(): 集合的最後一項;
eq(): 集合的指定項;
map(): 返回新的集合;
end(): 返回集合前一個狀態;
push(): 內部使用;
sort(): 內部使用;
splice(): 內部使用;
};
下面對jQuery對象中的部分屬性和方法詳細介紹一下:
1、constructor: 指定構造函數
構造函數屬於對象的一個屬性,對象創建時就自帶一個constructor屬性,該屬性指向對象對應的構造函數。先看兩種情況下constructor的值:
第一種情況:
function aaa(){}
var Oa = new aaa();
console.log(Oa.constructor); // function aaa(){}
第二種情況,往構造函數上添加原型屬性和方法:
function aaa(){}
aaa.prototype = {
name : "sean",
age : 21
};
var Oa = new aaa();
console.log(Oa.constructor); // function Object() { [native code] }
我們發現第二種情況下,我們通過這種方式給構造函數添加原型屬性和方法,改變了其原型屬性,因此對象的constructor指向也改變了。這時就需要修正其constructor屬性。
function aaa(){}
aaa.prototype = {
name : "sean",
age : 21
};
aaa.prototype.constructor = aaa;
var Oa = new aaa();
console.log(Oa.constructor); // function aaa(){}
修正過後的對象的constructor仍然指向其對象的構造函數。上面的jQuery.prototype中的constructor也是起相同的作用。
2、toArray(): 轉數組
該方法就是將獲取的json對象轉成數組。先來看一下其用法:
<div>1</div>
<div>2</div>
<div>3</div>
$(function(){
console.log($("div")); //Object[div, div, div]
console.log($("div").toArray()); // [div, div, div]
});
第一個打印出來的是一個對象,通過toArray()
方法之後轉成了數組。接下來介紹一下詳細的原理。
文檔中對jQuery對象toArray()
方法的定義如下:
只是用了一個JavaScript中數組的一個原型方法slice()
,通過call()
函數改變其上下文運行環境,this指定了運行環境爲當前對象。
再回顧一下slice()方法:slice()用於截取數組中的一部分,在只有一個參數的情況下, slice()方法返回從該參數指定位置開始到當前數組末尾的所有項。如果有兩個參數,該方法返回起始和結束位置之間的項——但不包括結束位置的項。當沒有傳入參數時,起始位置和結束位置將會自動變爲start = 0; end = this.length;。
再仔細看一眼$("div")
獲得的類數組對象:
其中存在一個length屬性,正好爲3,因此截取前面三個元素,然後組成數組。
3、pushStack(): JQ對象的入棧;
源碼(220~231行):
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
ret.context = this.context;
// Return the newly-formed element set
return ret;
},
pushStack()方法在jQuery外部用到的比較少,但是在jQuery內部確實經常用到,結合文檔中的註釋我們來逐行分析一下:
var ret = jQuery.merge( this.constructor(), elems );
jQuery的merge()方法表示將兩個數組或類數組對象合併,this.constructor指向構造函數jQuery(),這個行的作用就是根據傳入的jQuery對象創建一個新的jQuery對象。
ret.prevObject = this;
ret.context = this.context;
爲新創建的對象設置prevObject屬性,這個屬性會存儲pushStack之前的jQuery對象,所以如果你對jQuery對象進行了多次查找操作,是可以順着prevObject返回的。保持對前一個對象的引用。context是記錄上下文,如果不存在多個window,可以暫時不理會。最後返回ret。、
舉例說明一下pushStack()的使用:
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
$("#div1").pushStack($("#div2")).css("background","red");
上述程序最終是把div2
的背景顏色變成紅色。如果我們又要在此基礎上改變div1
的背景色呢?我們知道先從棧裏彈出來的是div2
,根據前面的分析,div2
通過prevObject屬性保持了對div1
的引用,因此如果我們需要改變div1
的背景色,下面可以實現:
$("#div1").pushStack($("#div2")).prevObject.css("background","red");
當然這種方法是隻是用於說明參數,實際應用中,我們是不會寫成這樣。除了prevObject屬性,還有一個方法,也能達到這個效果,就是end()方法,該方法一般與pushStack()方法配套使用。
4、end(): 返回集合前一個狀態
源碼(271~273行):
end: function() {
return this.prevObject || this.constructor(null);
},
源碼只有一行,就是返回prevObject 屬性引用的對象,如果沒有,則返回空對象。下面的寫法也能達到上面改變div1
背景色的效果:
$("#div1").pushStack($("#div2")).end().css("background","red");
5、slice(): 集合的截取
源碼(247~249行):
slice: function() {
return this.pushStack( core_slice.apply( this, arguments ) );
},
我們發現slice()方法就用到了pushStack()方法,主要就是利用JavaScript的原生slice()方法來對類數組對象進行截取,然後在進行入棧操作。我們以例子來說明:還是上面的三個div,我們進行以下操作:
$("div").slice(1,3).css("background","red");
這樣就是將第二個和第三個div的背景色變成紅色。具體過程是:首先$("div")
獲取到的是三個div,slice(1,3)
操作就是截取第二個和第三個div,然後對其進行入棧操作,所以這時候,在棧最外層的就是截取的第二個和第三個div,css()也是對這兩個div起作用。
既然是pushStack()操作,那麼當然可以配套end()使用,後面加上end(),就是對$("div")
獲取到的是三個div進行操作了,下面語句是改變三個div的顏色:
$("div").slice(1,3).css("background","red").end().css("color","yellow");
init(): 初始化以及管理參數,也就是選擇器的處理,是jQuery中比較重要的一部分,後續會專門進行分析。
下一章會對get()和eq()進行分析和比較。