前面基本将jQuery入口子產品中的jQuery建立(init函數)搞清楚了,在jQuery源碼中,接下來是對一些jQuery執行個體對象方法的定義。
比如
size //傳回對象中元素個數
toArray() //将jQuery對象轉換為數組
get() //擷取到jQuery對象中對應位置的元素
pushStack() //模拟的棧
each() //類似于for循環,對每個元素進行操作
ready() //DOM加載完成時觸發的函數
first() //擷取jQuery對象(集)的第一個元素
last() //擷取jQuery對象(集)中的最後一個元素
eq(num) //擷取jQuery對象(集)中的第num個元素
end() //用于回溯
map() //類似于數組的進階方法map(),即對應元素對應操作
push() //類似于數組的push
slice() //類似于數組方法
splice() //類似于數組方法
//後面這三種方法隻是供内部使用的
下來對于一些重要函數或比較難了解的函數做一分析。
pushStack方法
首先我們得知道這個函數是幹嘛的?
舉個例子:
$('div').pushStack($('ul'));
·
可以看到,最終得到的元素是ul,并且其jQuery對象有一個prevObject屬性,也是一個對象$(‘div’)。
從這不難看出,這類似與一個棧的結構
目前能得到的是棧頂的
$('ul')
,而
$('ul')
的prevObject是
$('div')
。那麼為什麼要這麼做呢?
之前在慕課網上看到過說,jQuery中有回溯的概念,而且我們也經常會用到的,就是end()函數。
比如:
//所有的li元素設border
$('ul').children().css('border', '1px solid black');
//所有的li元素設border和背景顔色
$('ul').children().css('border', '1px solid black').css('background-color', 'pink')
//li元素設border,ul 元素設背景顔色
$('ul').children().css('border', '1px solid black').end().css('border', '1px solid red')
//li元素設border,ul 元素設背景顔色
$('ul').children().css('border', '1px solid black').end().css('background-color', 'blue')
可以看到end()函數相當于彈棧(出棧)的作用,傳回的是棧頂元素的底下的那個元素。
它的源碼也很簡單:(就是傳回目前元素的prevObject)
return this.prevObject || this.constructor(null);
而end()函數的實作完全是基于pushStack的,沒有pushStack構造好這個資料結構,那麼end()也不可能這麼容易就實作。
下來我們看一下pushStack是如何來實作的。記住:類似于棧,那麼原理上就是後進先出的原則。
pushStack : function( elems, name, selector ){
// 建立一個空的jQuery對象
var ret = this.constructor();
//将要壓棧的元素存到ret裡面,變成一個數組
if ( jQuery.isArray( elems ) ) {
push.apply( ret, elems );
} else {
jQuery.merge( ret, elems );
}
//将上一個對象設為ret的prevObject對象
ret.prevObject = this;
ret.context = this.context;
//暫時不了解name的作用.
if ( name === "find" ) {
ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
}
// Return the newly-formed element set
return ret;
}
直覺上看,pushStack就做了這麼一件事:
其實依賴pushStack的函數很多,像上面提到的一些方法:
toArray() //将jQuery對象轉換為數組
eq(num) //擷取jQuery對象(集)中的第num個元素
end() //用于回溯
map() //類似于數組的進階方法map(),即對應元素對應操作
slice() //類似于數組方法
toArray方法
//調slice方法,類似于數組,它是對數組截取某一段的方法,傳回新數組
return slice.call( this, );
slice方法
舉個例子:
$('li').slice(,)
這裡對選擇到的兩個li元素進行截取,隻取第一個li,可以看到slice傳回的結果
結果中得到的對象,有prevObject屬性,還有selector,context,可以想像得到該方法也是調用了pushStack方法。具體源碼如下:
return this.pushStack( slice.apply( this, arguments ),
"slice", slice.call(arguments).join(",") );
看到這,貌似可以了解pushStack源碼中的name和傳回的selector的含義了,可能這隻是一個辨別,其實真正沒有實際的作用。
在slice源碼裡面,先是利用數組原生的slice方法去分割,注意apply 方法的用途,改變函數作用域。 然後再把分割得到的元素(集)壓入棧,便于回溯。也就是說,加入想通過鍊直接對所有的元素進行操作時,不用重新去擷取,直接調end()函數回溯就可以了,這樣的好處是對性能不會有壞的影響。而如果重新去擷取,相當于又建立了jQuery對象,如果很多這種操作,對記憶體需求是很大的,必然會影響性能。
eq(num)方法
取對象(集)或數組中的第num個元素。
eq: function(i){
i = +i;
return i === - ?
this.slice( i ) :
this.slice( i, i + );
} //1.7.2版本調的是slice方法,而2.0版本調的是pushStack方法,并直接取this[i]
map()方法
在應用層的用法:
可以看到,傳回的是一個新的對象,并且也是有prevObject屬性。并且map裡面的回調函數對于選中的每一個元素都進行了操作。
源碼:
map: function( callback ) {
//在源碼中,map函數調了底層的jQuery.map方法。
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
}
上面這些方法都是在jQuery對象上的方法,之是以能夠共享,是因為
jQuery.fn = jQuery.prototype = jQuery.fn.init.prototype
這是非常重要的一點。今天就先整理這麼多吧,後面待續。。。。