這是每個框架都遇到的問題,是使用原型擴展實現鏈式調用,仍是把方法都綁定都一個對象中。若是使用原型擴展就意味着與其餘全部走這條路的框架爲敵,在這條路上有兩個使人望而生畏的對手——Prototype與mootools。若是把方法都綁定都一個對象中(我一般稱之爲命名空間對象),方法調用起來就不那麼優雅,即便是jQuery,也只能讓實現節點的鏈式操做。但一個框架所能達到的高度,是由它的基礎設施決定。jQuery在它所涉及的方面算是作得盡善盡美了,但有沒有想到,mootools實現與此相同的功能,所需的代碼少多了。這是由於jQuery就一個jQuery對象在幹活,而 mootools那邊卻都是武裝到牙齒的Array,String,Number,Class,Event,Element等一大堆對象。原型擴展的好處顯然易見,咱們直接就能夠在字面量上實現鏈式操做。若是是第二種,想實現鏈式操做,就須要在一個自定義對象進行原型擴展,但這也意呋着鏈式操做只能在實例的方法中進行,須要new一下。John Resigs想歪腦,搞了個無new實例化,減輕這種調用的痛苦(可能對其餘語言的人來講,一大堆分開的方法調用不算什麼,但在JS界,已經大規模使用鏈式操做,而你寫JS時仍是一個個方法地調用,明顯是不合潮流,會「被落後」!)
// jQuery
$.trim(" abc ");
// Google Closure Library
goog.string.trim(" abc ");
// Dojo Toolkit
dojo.string.trim(" abc ");
像jquery這樣分層結構不明顯的庫,會把這些工具方法都依附到命名空間對象上,但若是庫的規模很大,像Google Closure那樣就不行,會很亂很亂,調用方法時內部有一個方法尋找的過程,這裏會出現性能耗消。因爲直接是返回沒有什麼擴展的原生對象,第二次調用就可能「鏈」不起來了。
//假設我已爲jQuery添加了capitalize方法
$.capitalize($.trim(" abc "));
是否是很醜鄙呢?!但如今我想通了,個人框架如今還很弱小,絕對不能與Prototype、mootools爲敵,要不就會被它們扼殺於襁褓之中。我想了很久,把原生對象的(原型)方法劃分爲三個層次。第一種是全部瀏覽器都支持的,第二種是IE6不支持,但已列入ECMA草案的,如 javascript1.6的迭代器,它們不使用新的語言特徵就能模擬出來的,第三種是自定義方法,話需如此,有些方法,許多主流框架都實現了的,如 string的capitalize、camelize、substitute,array的unique、flatten,object的each或 forEach。第一種咱們不用管,第二種只是個兼容的問題,實現方法大同小異,反正效果出來是同樣就好了。第三種若是也加入到原型中,很容易與其餘類庫形成命名衝突,由於它們有時僅僅是名字同樣,要達到的目的徹底是兩碼事。嗯,又是時候隆重推介我全新的鏈式操做。
咱們知道,query之因此能鏈式調用,它的方法每次都返回擁有全部方法的對象。這種對象,咱們稱之爲實例,由於它能夠廉價地調用其原型鏈上的方法。咱們反過來想,原型鏈其實也是一個個對象。咱們能夠獨立地實現這些對象,我稱之爲
擴展方法集合體
,如stringExt、numberExt、arrayExt。剩下的是「實例」問題,「實例」能擁有全部方法,包括原生的以及自定義的。很明顯,讓一個對象幹四種原生對象的活是不現實的,我相應地搞了四種對象。這些對象,我稱之爲
代理對象
,都是方法集體合,但這些方法與擴展方法集合體的大相徑庭,它們都是代理方法,裏面的邏輯如出一轍,不一樣的是函數體上附了一個方法名,如 「toArray」、"camelize"啦。最開始的時候,咱們把這個操做對象放進一個入口函數(chain)。這實際上是一個適配器,但爲了簡單起見,我暫時略去這些邏輯,在裏面直接調用
鏈式函數
(adjustProxy)就算。此函數會根據操做對象的類型,選擇不一樣的
代理對象
,或者乾脆不作,直接返回。最着就等這個代理對象的某個方法被調用了,我說過它只是代理方法,惟一不一樣的是方法名與所在對象。被調用時,它會先從本身身上獲得方法名與從內部的this那裏獲得操做對象target與其類型。就算這類型其實也能夠經過計算獲得,但既然上次已計算過,就不謂重複而已。有了方法名,咱們就斷定操做對象是否天生支持此方法,沒有則從相應
擴展方法集合體
尋找相應同名方法。而後是調用方法,把獲得的結果再放進
鏈式函數 (adjustProxy)中……這樣就實現鏈式操做了。 分享兩個高手寫的 $(document).ready(function(){ //這個就是傳說的ready $(".stripe tr").mouseover(function(){ //若是鼠標移到class爲stripe的表格的tr上時,執行函數 $(this).addClass("over");}).mouseout(function(){ //給這行添加class值爲over,而且當鼠標一出該行時執行函數 $(this).removeClass("over");}) //移除該行的class $(".stripe tr:even").addClass("alt"); //給class爲stripe的表格的偶數行添加class值爲alt }); $(function(){ $(".has_children").click(function(){ $(this).addClass("highlight") .children("a") .show().end() .siblings() .removeClass("highlight") .children("a") .hide(); }); }); var tdObj = $(this); var text = tdObj.html(); tdObj.html(""); var inputObj = $("<input type='text' />").css("border-width","0") .css("font-size","16px").width(tdObj.width()) .css("background-color",tdObj.css("background-color")) .val(text).appendTo(tdObj);