摘要:在對象的內部,有著一個對象棧,用來維護所有已經操作過的對象。這樣來想一想,如果每一個對象都有一個指針指向上一個對象的話,也就間接組成了一個對象棧。
歡迎來我的專欄查看系列文章。
學習了 prevObject 之后發現,我之前寫的一篇博客介紹 pushStack 函數那個內容是有問題的。本來我以為這個 pushStack 函數就是一個普通的函數,它接受一個 DOM (數組)參數,把該參數合并到一個 jQuery 對象中并返回該 jQuery 對象。
后來我也疑惑過一段時間,為什么看不到這個函數的使用,而且為什么要把它放到 jQuery.fn 上,直到今天,才恍然大悟。
jQuery 的 prevObject 對象當我們新建一個 jQuery 對象的時候,都會在其屬性中發現一個 prevObject 的屬性,如果單單從名字來看的,“前一個對象”,那么它到底是怎么用的呢。
在 jQuery 對象的內部,有著一個 jQuery 對象棧,用來維護所有已經操作過的 jQuery 對象。這樣子的話可以寫出很流暢的 jQuery 代碼,比如操作父元素,操作子元素,再回到父元素的時候就很方便。
但實際上,這個棧是不存在的,我們知道數組可以當作棧或隊列來使用,是不是說 jQuery 內部有這么個數組來存放這個對象棧呢。答案是 no,為什么,因為沒必要這么麻煩。這樣來想一想,如果每一個 jQuery 對象都有一個指針指向上一個對象的話,也就間接組成了一個 jQuery 對象棧。如果棧只有一個元素,prevObject 就默認指向 document。prevObject 是干什么用的,就是來實現對象棧的。比如:
標題
container
重點
對于上面的 html:
var $view = $("#view"); // $header 是由 $view 操作得到的 var $header = $view.find(".header"); $header.prevObject === $view; // true
不過在使用的時候,都是忽略對象棧而定義不同的 jQuery 對象來指向父元素和子元素,就像上面的例子那樣,既然定義了 $view 和 $header,就不需要 prevObject 了。
jQuery.fn.end 和 jQuery.fn.addBack這兩個函數其實就是 prevObject 的應用,舉個例子就能弄明白了,仍然是上面的那個 html:
$("#view").find(".header").css({"color": "red"}) .end() .find(".espe").css({"color": "white"})
加了 end之后,當前執行的 jQuery 對象就變成 $("#view")了,所以可以繼續執行 find 操作等等,如果不加的話,這段話是不能執行成功的。可見,如果這樣子寫 jQuery 不僅寫法優雅,而且還很高效。
end 和 addBack 是有區別的,end() 函數只是單純的進行出棧操作,并返回出棧的這個 jQuery 對象,而 addBack() 函數不會執行出棧,而是把棧頂對象和當前的對象組成一個新對象,入棧:
$("#view").find(".header").nextAll() .addBack() .css({"color": "red"}) // 顏色全紅
上面的代碼,會使得 #view 的三個子元素的顏色都設置為紅色。
相關函數源碼重新來看下 pushStack 函數吧,這個函數不僅在 fn.find() 函數中出現,好多涉及 jQuery dom 操作的原型函數都出現了,而且之前介紹的時候,忽略了一個重要的部分 prevObject 對象:
jQuery.fn.pushStack = function (elems) { // 將 elems 合并到 jQuery 對象中 var ret = jQuery.merge(this.constructor(), elems); // 實現對象棧 ret.prevObject = this; // 返回 return ret; }
pushStack 生成了一個新 jQuery 對象 ret,ret 的 prevObject 屬性是指向調用 pushStack 函數的那個 jQuery 對象的,這樣就形成了一個棧鏈,其它原型方法如 find、nextAll、filter 等都可以調用 pushStack 函數,返回一個新的 jQuery 對象并維持對象棧。
我們知道了所有 jQuery 方法都有一個 prevObject 屬性的情況下,來看看 end 方法:
jQuery.fn.end = function () { return this.prevObject || this.constructor(); }
還有 addBack 方法:
jQuery.fn.addBack = function (selector) { // 可以看出有參數的 addBack 會對 prevObject 進行過濾 return this.add(selector == null ? this.prevObject : this.prevObject.filter(selector)); }
里面穿插了一個 fn.add 方法:
jQuery.fn.add = function (selector, context) { return this.pushStack( jQuery.uniqueSort( jQuery.merge(this.get(), jQuery(selector, context)))); }
應該不需要解釋吧,源碼一清二楚。
總結我之前就已經說過,很少會使用 end 或 pushStack 方法,而在 jQuery 內部的原型方法中,比如 find、nextAll、filter 等,被頻繁使用,這種封裝一個 jQuery 的方法很棒,會把對象棧給維護得很好。無論如何,這就是 jQuery 的魅力吧!
參考jQuery 2.0.3 源碼分析 回溯魔法 end()和pushStack()
jQuery API .end()
jQuery API .addBack()
本文在 github 上的源碼地址,歡迎來 star。
歡迎來我的博客交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81701.html
摘要:用來存放每一個可能的結果最終結果深度優先遍歷剪枝當遍歷到底個數是,如果的元素個數剩余元素個數時,就不滿足條件了中元素個數達到,表示深度優先遍歷到達最深處了。 ?77. 組合77. 組合77. 組合 給定兩個整數?n?和?k,返回范圍?[1, n]?中所有可能的?k?個數的組合。 你可以按?任...
摘要:忍者級別的函數操作對于什么是匿名函數,這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數是一個很重要且具有邏輯性的特性。通常,匿名函數的使用情況是創建一個供以后使用的函數。 JS 中的遞歸 遞歸, 遞歸基礎, 斐波那契數列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執行機制 本文的目的就是要保證你徹底弄懂javascript的執行機制,如果...
摘要:事件機制在講事件機制之前呢我們有一個很重要的東西要先講那就是如何實現事件委托代理只有必須先明白了如何實現一個事件委托我們才能更好的去實現和在我看來和里最難實現的就是他的事件委托以上是我對整個委托的實現當然在這只做了非常簡單的實現沒有對很多 Lesson-8 事件機制 在講事件機制之前呢,我們有一個很重要的東西要先講,那就是如何實現事件委托(代理). 只有必須先明白了如何實現一個事件委...
摘要:事件機制在講事件機制之前呢我們有一個很重要的東西要先講那就是如何實現事件委托代理只有必須先明白了如何實現一個事件委托我們才能更好的去實現和在我看來和里最難實現的就是他的事件委托以上是我對整個委托的實現當然在這只做了非常簡單的實現沒有對很多 Lesson-8 事件機制 在講事件機制之前呢,我們有一個很重要的東西要先講,那就是如何實現事件委托(代理). 只有必須先明白了如何實現一個事件委...
閱讀 1938·2021-11-24 09:39
閱讀 3278·2021-09-22 14:58
閱讀 1162·2019-08-30 15:54
閱讀 3315·2019-08-29 11:33
閱讀 1788·2019-08-26 13:54
閱讀 1598·2019-08-26 13:35
閱讀 2468·2019-08-23 18:14
閱讀 762·2019-08-23 17:04