網頁制作poluoluo文章簡介:javascript陣營裡面出現了越來越多的優秀的框架,大大簡化了我們的開發工作,在我們使用這些框架的時候是不是也應該飲水思源想想它們都是怎樣構建起來的呢?
隨著時代發展,javascript陣營裡面出現了越來越多的優秀的框架,大大簡化了我們的開發工作,在我們使用這些框架的時候是不是也應該飲水思源想想它們都是怎樣構建起來的呢?如果你不滿足於僅僅是使用一些現成的API,而是深入了解它們內部的實現機制(照某人的說法, API是貶值最快的東西),最好的辦法就是閱讀它們的源代碼了,前提是你讀得懂。
最近兩天研究了一下jQuery的源碼,在這裡將本人一些粗淺認識分享出來,不當之處請各位指正。好了,下面我們就來看看jQuery大概是怎樣工作的,我假定你已經具備了一些基本的javascript知識,如果基礎不夠俺推薦你閱讀《JavaScript高級程序設計》和《悟透JavaScript》這兩本書。本文不適合對js裡面的類、對象、函數、prototype等概念沒有了解的朋友。
我們從最開始的說起:
首先構造一個對象給使用者,假定我們這個框架叫 Shaka ( 俺的名字;) )
var Shaka = function(){}; 這裡我們創建了一個空函數,裡面什麼也沒有,這個函數實際上就是我們的構造函數。為了讓我們生成的對象能夠調用在prototype裡定義出來的方法, 我們需要用原型的方式(把Shaka當作是一個類)給Shaka添加一些方法,於是定義:
Shaka.fn = Shaka.prototype = {};
這裡的Shaka.fn相當於Shaka.prototype的別名,方便以後使用,它們指向同一個引用。
OK,我們添加一個sayHello的方法, 給Shaka添加一個參數,這樣這個框架最基本的樣子已經有了,如果它有生命的話那麼它現在是1歲, 看代碼:
運行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]
好啦,先別激動, 我們注意到這個框架跟jQuery在使用上是有一些差別的, 比如在jq 中我們可以這樣寫:
jQuery('#myid').someMethod();
這是怎樣做到的呢, 也就是說 jQuery()這個構造函數返回了一個jQuery的對象實例,因此我們可以在上面調用它的方法,所以Shaka的構造函數應該返回一個實例,它看起來應該是這個樣子:
var Shaka = function(){ return //返回Shaka的實例; };
那麼我們要如何取得一個Shaka的實例呢, 我們先來回顧一下使用prototype方式來模擬類的時候 var someObj = new MyClass(); 這個時候實際上是創建一個新對象someObje,把新對象作為this指針,調用 MyClass函數,即類的構造函數, 然後 someObj 就獲得了在 MyClass.prototype裡面定義的方法, 這些方法內的this指針指當前對象實例。
網頁制作poluoluo文章簡介:javascript陣營裡面出現了越來越多的優秀的框架,大大簡化了我們的開發工作,在我們使用這些框架的時候是不是也應該飲水思源想想它們都是怎樣構建起來的呢?
在jQuery中使用了一個工廠方法來創建一個實例,這個方法位於jQuery.prototype中, 現在我們重新來定義Shaka.prototype, 給它添加一個init方法用於返回一個Shaka的實例, 並且把Shaka的構造函數稍稍改變一下:
OK,現在我們的小寶寶變成大一點的寶寶了,打個招呼先:
運行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]
嗯,好象有點樣子了,但是光這樣還不行,來點實際的, 我們在新框架中實現jquery裡val()方法的部分功能,這個方法不加參數調用時返回指定ID的input的值,加參數時為設定這個input的值,與jQery一樣,我們約定使用id來查找對象時使用"#"符號。把要查找的目標ID作為構造函數的參數傳進去,我們給Shaka.prototype添加一個val()方法, 給Shaka添加一個selector的屬性用於存儲我們要查找的目標。
Shaka.fn = Shaka.prototype = {
init: function(selector) { this.selector = selector; return this; },
val: function(newValue) { //方法實現代碼 }
};
var Shaka = function(selector) { return new Shaka.fn.init(selector); };
運行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]
網頁制作poluoluo文章簡介:javascript陣營裡面出現了越來越多的優秀的框架,大大簡化了我們的開發工作,在我們使用這些框架的時候是不是也應該飲水思源想想它們都是怎樣構建起來的呢?
到目前為止我們已經創建一個可以工作的框架雛形,為了使程序可以更方便地被調用,比如jQuery可以使用$符號來簡寫,我們也弄一個,在此之前我們先來回顧兩個東西:
1. 我們在腳本中可以這樣定義變量:
var foo = 'someThing';
bar = 'otherthing';
這樣兩種寫法都是合法的,但是意義完全不同, 第一個語句創建了一個新的變量,而第二個是定義了window對象的一個屬性,相當於window.bar = 'otherthing';, 因此我們想使我們的Shaka具有這樣的調用方式能力: $.someMethod();就需要將Shaka設置為window的一個屬性, 於是我們的Shaka構造函數就得寫成這樣:
var Shaka = window.Shaka = window.$ = function(selector) { return new Shaka.fn.init(selector); };
2. javascript的匿名函數.
創建並執行一個匿名函數的基本形式: (function(){ alert('Hello World!'); })(); 為什麼要用到匿名函數呢,因為我們不想把Shaka的內部實現暴露出來,這樣容易與其它代碼沖突,只提供一個單一的入口,我們可以這樣測試一下:
運行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]
然後,還有一個問題需要解決,俺們的框架做出來了但是還很簡陋,在這之前我們需要讓它與其它的框架協同工作,因此帶來一個問題, 如果我們都使用$作為簡寫形式就會沖突了, 象jQuery一樣,我們需要提供一個noConfilit的方法“出讓”$的使用權。在我們的程序最開始處加入下面的代碼:
var _$ = window.$;
意思是將此前定義的$對象引用放到 _$ 中, 然後我們再給Shaka擴展一個方法出來, 如果其它開發者需要自行擴展的話也可以使用這個方式(jQuery的extend方法提供了更為強大的功能,請大家自行研究):
(function($){ //extend method definition. })(Shaka);
意思是將Shaka作為這個匿名函數的參數來調用這個方法。
前面我們講過 Shaka.fn 就是 Shaka.prototype 的別名,因此我們要在Shaka.prototype 裡面添加新的方法就可以寫成這樣:
(function($){
$.fn.noConflict = function(){
window.$ = _$;//把$還給在開始處取得的引用.
};
})(Shaka);
現在我們來看一個完整的:
運行代碼框
[Ctrl+A 全部選擇 提示:你可先修改部分代碼,再按運行]
現在好象不錯了,我們的Shaka baby已經5歲了;) , 當然這還只是個簡陋的東西,要實現健壯而強大的功能還需要付出很多努力, 希望諸位爹媽把自己的孩子培養成人才, good luck!
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)創建的對象具有init方法的prototype指向對象的方法 , 因此我們將init方法的prototype指向 Shaka的prototype, 這樣創建出來的對象就具有了Shaka.prototype裡面定義的方法。