摘要: 本文由簡(jiǎn)到繁地介紹了以jQuery作為藍(lán)本的js框架開(kāi)發(fā)步聚, 希望借助本文大家對(duì)jQuery這樣的框架內(nèi)部有一個(gè)大致的認(rèn)識(shí)。 隨著時(shí)代發(fā)展,,javascript陣營(yíng)里面出現(xiàn)了越來(lái)越多的優(yōu)秀的框架,,大大簡(jiǎn)化了我們的開(kāi)發(fā)工作,在我們使用這些框架的時(shí)候是不是也應(yīng)該飲水思源想想它們都是怎樣構(gòu)建起來(lái)的呢,?如果你不滿足于僅僅是使用一些現(xiàn)成的API,,而是深入了解它們內(nèi)部的實(shí)現(xiàn)機(jī)制(照某人的說(shuō)法, API是貶值最快的東西),最好的辦法就是閱讀它們的源代碼了,,前提是你讀得懂,。 最近兩天研究了一下jQuery的源碼,,在這里將本人一些粗淺認(rèn)識(shí)分享出來(lái),不當(dāng)之處請(qǐng)各位指正,。好了,,下面我們就來(lái)看看jQuery大概是怎樣工作的,我假定你已經(jīng)具備了一些基本的javascript知識(shí),,如果基礎(chǔ)不夠俺推薦你閱讀《JavaScript高級(jí)程序設(shè)計(jì)》和《悟透JavaScript》這兩本書,。本文不適合對(duì)js里面的類、對(duì)象,、函數(shù),、prototype等概念沒(méi)有了解的朋友。 我們從最開(kāi)始的說(shuō)起: 首先構(gòu)造一個(gè)對(duì)象給使用者,,假定我們這個(gè)框架叫 Shaka ( 俺的名字;) ) var Shaka = function(){}; 這里我們創(chuàng)建了一個(gè)空函數(shù),,里面什么也沒(méi)有,這個(gè)函數(shù)實(shí)際上就是我們的構(gòu)造函數(shù),。為了讓我們生成的對(duì)象能夠調(diào)用在prototype里定義出來(lái)的方法, 我們需要用原型的方式(把Shaka當(dāng)作是一個(gè)類)給Shaka添加一些方法,于是定義: Shaka.fn = Shaka.prototype = {}; 這里的Shaka.fn相當(dāng)于Shaka.prototype的別名,,方便以后使用,,它們指向同一個(gè)引用。 OK,,我們添加一個(gè)sayHello的方法, 給Shaka添加一個(gè)參數(shù),,這樣這個(gè)框架最基本的樣子已經(jīng)有了,如果它有生命的話那么它現(xiàn)在是1歲, 看代碼: [Ctrl+A 全部選擇 提示:你可先修改部分代碼,,再按運(yùn)行] 好啦,,先別激動(dòng), 我們注意到這個(gè)框架跟jQuery在使用上是有一些差別的, 比如在jq 中我們可以這樣寫jQuery('#myid').someMethod(); 這是怎樣做到的呢, 也就是說(shuō) jQuery()這個(gè)構(gòu)造函數(shù)返回了一個(gè)jQuery的對(duì)象實(shí)例,因此我們可以在上面調(diào)用它的方法,,所以Shaka的構(gòu)造函數(shù)應(yīng)該返回一個(gè)實(shí)例,,它看起來(lái)應(yīng)該是這個(gè)樣子: var Shaka = function(){ return //返回Shaka的實(shí)例; }; 那么我們要如何取得一個(gè)Shaka的實(shí)例呢, 我們先來(lái)回顧一下使用prototype方式來(lái)模擬類的時(shí)候 var someObj = new MyClass(); 這個(gè)時(shí)候?qū)嶋H上是創(chuàng)建一個(gè)新對(duì)象someObje,把新對(duì)象作為this指針,,調(diào)用 MyClass函數(shù),即類的構(gòu)造函數(shù), 然后 someObj 就獲得了在 MyClass.prototype里面定義的方法, 這些方法內(nèi)的this指針指當(dāng)前對(duì)象實(shí)例,。 在jQuery中使用了一個(gè)工廠方法來(lái)創(chuàng)建一個(gè)實(shí)例,這個(gè)方法位于jQuery.prototype中, 現(xiàn)在我們重新來(lái)定義Shaka.prototype, 給它添加一個(gè)init方法用于返回一個(gè)Shaka的實(shí)例, 并且把Shaka的構(gòu)造函數(shù)稍稍改變一下: var Shaka = function(age) { return new Shaka.fn.init(age); }; Shaka.fn = Shaka.prototype = { init: function(age) { this.age = age; return this; }, sayHello: function() { alert('I am a little baby, my age is ' + this.age + ' years old.'); } }; Shaka.fn.init.prototype = Shaka.fn;//這里new Shaka.fn.init(age)創(chuàng)建的對(duì)象具有init方法的prototype指向?qū)ο蟮姆椒?, 因此我們將init方法的prototype指向 Shaka的prototype, 這樣創(chuàng)建出來(lái)的對(duì)象就具有了Shaka.prototype里面定義的方法,。 OK,,現(xiàn)在我們的小寶寶變成大一點(diǎn)的寶寶了,打個(gè)招呼先: [Ctrl+A 全部選擇 提示:你可先修改部分代碼,,再按運(yùn)行] 嗯,,好象有點(diǎn)樣子了,但是光這樣還不行,,來(lái)點(diǎn)實(shí)際的, 我們?cè)谛驴蚣苤袑?shí)現(xiàn)jquery里val()方法的部分功能,,這個(gè)方法不加參數(shù)調(diào)用時(shí)返回指定ID的input的值,,加參數(shù)時(shí)為設(shè)定這個(gè)input的值,與jQery一樣,,我們約定使用id來(lái)查找對(duì)象時(shí)使用"#"符號(hào),。把要查找的目標(biāo)ID作為構(gòu)造函數(shù)的參數(shù)傳進(jìn)去,我們給Shaka.prototype添加一個(gè)val()方法, 給Shaka添加一個(gè)selector的屬性用于存儲(chǔ)我們要查找的目標(biāo),。:Shaka.fn = Shaka.prototype = { init: function(selector) { this.selector = selector; return this; }, val: function(newValue) { //方法實(shí)現(xiàn)代碼 } }; var Shaka = function(selector) { return new Shaka.fn.init(selector); }; [Ctrl+A 全部選擇 提示:你可先修改部分代碼,,再按運(yùn)行] 休息一下,順便插播一條廣告: 俺的blog http://darkangle.cnblogs.com ;)到目前為止我們已經(jīng)創(chuàng)建一個(gè)可以工作的框架雛形,,為了使程序可以更方便地被調(diào)用,,比如jQuery可以使用$符號(hào)來(lái)簡(jiǎn)寫,我們也弄一個(gè),,在此之前我們先來(lái)回顧兩個(gè)東西: 1. 我們?cè)谀_本中可以這樣定義變量: var foo = 'someThing'; bar = 'otherthing'; 這樣兩種寫法都是合法的,,但是意義完全不同, 第一個(gè)語(yǔ)句創(chuàng)建了一個(gè)新的變量,而第二個(gè)是定義了window對(duì)象的一個(gè)屬性,,相當(dāng)于window.bar = 'otherthing';, 因此我們想使我們的Shaka具有這樣的調(diào)用方式能力: $.someMethod(),;就需要將Shaka設(shè)置為window的一個(gè)屬性, 于是我們的Shaka構(gòu)造函數(shù)就得寫成這樣: var Shaka = window.Shaka = window.$ = function(selector) { return new Shaka.fn.init(selector); }; 2. javascript的匿名函數(shù). 創(chuàng)建并執(zhí)行一個(gè)匿名函數(shù)的基本形式: (function(){ alert('Hello World!'); })(); 為什么要用到匿名函數(shù)呢,因?yàn)槲覀儾幌氚裇haka的內(nèi)部實(shí)現(xiàn)暴露出來(lái),,這樣容易與其它代碼沖突,,只提供一個(gè)單一的入口,我們可以這樣測(cè)試一下:
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,,再按運(yùn)行] 然后,,還有一個(gè)問(wèn)題需要解決,俺們的框架做出來(lái)了但是還很簡(jiǎn)陋,,在這之前我們需要讓它與其它的框架協(xié)同工作,,因此帶來(lái)一個(gè)問(wèn)題, 如果我們都使用$作為簡(jiǎn)寫形式就會(huì)沖突了, 象jQuery一樣,我們需要提供一個(gè)noConfilit的方法“出讓”$的使用權(quán),。在我們的程序最開(kāi)始處加入下面的代碼:var _$ = window.$; 意思是將此前定義的$對(duì)象引用放到 _$ 中, 然后我們?cè)俳oShaka擴(kuò)展一個(gè)方法出來(lái), 如果其它開(kāi)發(fā)者需要自行擴(kuò)展的話也可以使用這個(gè)方式(jQuery的extend方法提供了更為強(qiáng)大的功能,,請(qǐng)大家自行研究): (function($){ //extend method definition. })(Shaka); 意思是將Shaka作為這個(gè)匿名函數(shù)的參數(shù)來(lái)調(diào)用這個(gè)方法。 前面我們講過(guò) Shaka.fn 就是 Shaka.prototype 的別名,,因此我們要在Shaka.prototype 里面添加新的方法就可以寫成這樣 (function($){ $.fn.noConflict = function(){ window.$ = _$;//把$還給在開(kāi)始處取得的引用. }; })(Shaka); 現(xiàn)在我們來(lái)看一個(gè)完整的: [Ctrl+A 全部選擇 提示:你可先修改部分代碼,,再按運(yùn)行] 現(xiàn)在好象不錯(cuò)了,我們的Shaka baby已經(jīng)5歲了;) , 當(dāng)然這還只是個(gè)簡(jiǎn)陋的東西,,要實(shí)現(xiàn)健壯而強(qiáng)大的功能還需要付出很多努力, 希望諸位爹媽把自己的孩子培養(yǎng)成人才, good luck! |
|
來(lái)自: 時(shí)光懶散 > 《從0開(kāi)始寫jQuery的框架》