jQuery.each({parent: function( elem ) { // 父元素var parent = elem.parentNode;return parent && parent.nodeType !== 11 ? parent : null; // DocumentFragment 11, DocumentType 10},parents: function( elem ) { // 祖先元素return jQuery.dir( elem, "parentNode" ); // 檢索所有父元素,直至document},parentsUntil: function( elem, i, until ) { // return jQuery.dir( elem, "parentNode", until );},next: function( elem ) { // 下一個兄弟元素return jQuery.nth( elem, 2, "nextSibling" ); // 從1開始計數,當前是第1個,為什麼要再搞一套不一致的索引方法呢?},prev: function( elem ) { // 上一個兄長元素return jQuery.nth( elem, 2, "previousSibling" );},nextAll: function( elem ) { // 所有的兄弟元素return jQuery.dir( elem, "nextSibling" );},prevAll: function( elem ) { // 所有的兄長元素return jQuery.dir( elem, "previousSibling" );},nextUntil: function( elem, i, until ) { // 所有的兄弟元素,但是不包括untilreturn jQuery.dir( elem, "nextSibling", until );},prevUntil: function( elem, i, until ) { // 所有的兄長元素,但是不包括untilreturn jQuery.dir( elem, "previousSibling", until );},siblings: function( elem ) { // 所有兄長、兄弟元素,不包括當前元素return jQuery.sibling( elem.parentNode.firstChild, elem ); // 父元素的第一個子項目的所有兄弟元素,排除當前元素elem// 取子項目childNodes然後過濾elem,效率更高},children: function( elem ) { // 所有的子節點,只包含Elementreturn jQuery.sibling( elem.firstChild ); // 第一個子項目的所有兄弟元素// 為什麼不直接取子項目呢?childNodes不是效率更高嗎?},contents: function( elem ) { // 所有的子節點,包含Element、Text、Commentreturn jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : // 如果是iframe,則取documentjQuery.makeArray( elem.childNodes ); // 將childNodes轉換數組,childNodes是偽數組,轉換後遍曆數組時可以避免對childNodes進行檢查,提高效能}}, function( name, fn ) {jQuery.fn[ name ] = function( until, selector ) {var ret = jQuery.map( this, fn, until ), // 將this中的元素,用fn處理,最後返回真正的數組,until用於過濾// The variable 'args' was introduced in// https://github.com/jquery/jquery/commit/52a0238// to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.// http://code.google.com/p/v8/issues/detail?id=1050args = slice.call(arguments); // 將arguments複製並轉為數組if ( !runtil.test( name ) ) { // 不以Until結尾selector = until; // 不需要參數until,只有一個參數selector,util只到這裡為止}if ( selector && typeof selector === "string" ) {ret = jQuery.filter( selector, ret ); // 對ret數組用selector進行過濾,只留下匹配的元素// jQuery.filter會調用jQuery.find.matches > Sizzle.matches > Sizzle,Sizzle尋找、過濾的結果已經經過排序、去重}/** * 排序、去重 * 首先要知道this是經過排序、且無重複 * 如果長度大於1,才需要判斷是否需要去重 * 如果name是 children contents next prev 之一,則不需要排序去重,因為這四個方法不會產生無序和重複的結果,為什麼呢? * 因為this中的元素是有序、去重的,所以的它子節點、兄弟、兄長,也都是有序、無重複的 * 但是parent parents parentsUntil nextAll prevAll nextUntil prevUntil siblings卻有可能產生重複、無序的元素 * * 可見這裡進行了最佳化,不可否則這種編碼習慣很精緻很贊,但是: * 即使不需要排序、去重的情況,也必然要經過這些漫長的判斷,就是一種浪費 * 這種多功能導致的複雜性和無謂的效能消耗,在jQuery中隨處可見 * 雖然沒有做詳盡的效能測試,其實也沒必要,但稍微給我有點“機關算盡太聰明,枉費了卿卿性命”的感覺 * 從剛開始讀源碼時的驚豔和崇拜,漸漸的能分辨其中的精髓與作者的權衡拿捏,jQuery的偉大不可否認, * 但是我們寫代碼的時候,要借鑒參考,也要思考取捨 * * 上邊的感觸僅供參考,我還處於能讀懂和能分析jQuery源碼的階段,不到自創一套類庫的境界, * 也許水平提高了jQuery不能滿足我的時候,再回頭看,興許是另一重感悟了。 */ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; // 去重// rparentsprev = /^(?:parents|prevUntil|prevAll)/// 因為前邊返回的結果是按照元素在文檔中的位置順序返回的,遇到rparentsprev則需要再反過來,方便使用if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {ret = ret.reverse(); // 倒序}return this.pushStack( ret, name, args.join(",") ); // 構造jQuery對象};}) |