javascript筆記:臨摹jQuery(二)

來源:互聯網
上載者:User

  在我前一篇部落格裡有位童鞋問了xQuery.fn.init.prototype = xQuery.fn;寫法的目的,這個問題在我臨摹jQuery時候也碰到過,最開始我是沒有加入這個方法,在firebug裡面,方法console.log(xQuery('').xquery);列印出的結果是:undefined,這就表明xquery屬性根本就沒有定義,我構建的xQuery對象只是保留了在xQuery.fn.init(selector,context);裡面存在的屬性,如是我做了下面的測試:

xQuery.fn = xQuery.prototype = {init:function(){return this;},tempquery:'1.0.1',length:23,size:function(){return this.length;}};console.log(xQuery().tempquery);//undefinedconsole.log(xQuery().length);//undefinedconsole.log(xQuery().size());//error:xQuery().size is not a function

  那麼xQuery.fn.init.prototype = xQuery.fn;作用到底是怎樣的?我做了下面一系列的測試:

  測試一:對於代碼:

   

var xQuery = function(selector,context){return new xQuery.fn.init(selector,context);}

   這是使用了javascript裡面的原廠模式構建對象,只不過這個工廠比較特別,讓人第一眼覺得是個迭代的調用的原廠模式,因此我寫了下面的測試代碼:

var xQuery = function(){return new tempQuery();};var tempQuery = function(){};tempQuery.prototype = {tempquery:'1.0.1',length:4,size:function(){return this.length;}};console.log(xQuery().tempquery);//1.0.1console.log(xQuery().length);//4console.log(xQuery().size());//4console.log(xQuery() instanceof xQuery);//false

  這裡我另起了一個對象tempQuery ,初始化了tempQuery 的原型鏈的屬性,那麼每次調用xQuery()就是在使用作為xQuery建構函式傳回值的tempQuery 對象。如果這麼做,就存在了javascript裡原廠模式的缺點了:1.會產生重複的相似對象,造成系統資源的浪費;2.xQuery對象識別的問題(例如:console.log(xQuery() instanceof xQuery);//false)。

  要解決這些問題,那麼xQuery的建構函式應該是構造自己本身,而不是每次構造都是一個新的對象,這樣的思路就能避免javascript原廠模式的缺陷,因此我又做了下面測試。

  測試二:

var xQuery = function(){       returnnew xQuery();//too much recursion new xQuery();//too much recursion,無限遞迴調用 };xQuery.prototype = {tempquery:'1.0.1',length:8,size:function(){return this.length;}};console.log(xQuery().tempquery);console.log(xQuery().length);console.log(xQuery().size());console.log(xQuery() instanceof xQuery);

  最終的結果是會在new xQuery();代碼處報出too much recursion new xQuery();//too much recursion,無限遞迴調用 的錯誤,也就是所謂的記憶體溢出了。這種寫法真白癡,如果不是為了驗證結果,我不會去寫這麼明顯的遞迴調用的代碼的。

  那麼有什麼更好的寫法了,如是我再看看jQuery源碼,發現它是使用到了prototype原型鏈來構造xQuery對象。因此就有下面測試代碼:

  測試三:

var xQuery = function(){return new xQuery.prototype.init();};xQuery.prototype = {init:function(){return this;},tempquery:'1.0.1',length:8,size:function(){return this.length;}};console.log(xQuery().tempquery);//undefinedconsole.log(xQuery().length);//undefinedconsole.log(xQuery() instanceof xQuery);//falseconsole.log(xQuery().size());//xQuery().size is not a function

  這種寫法就沒有報記憶體溢出的錯誤了,不過也沒有達到我們預期的效果xQuery().tempquery和xQuery.length都是undefined,xQuery() 的類型也不是xQuery,size()還沒有定義(這個我和文章前面沒寫xQuery.fn.init.prototype = xQuery.fn;的情況一樣),為什麼會有這樣的結果了?其實從javascript對象的理論老理解這種結果就很簡單了。原因分析如下:

  我們知道javascript裡面除了string,boolean等基本類型外其他都是object(對象),而對象的名稱只是該對象的在棧記憶體中的地址,換種說法就是該對象的引用。其實我們程式中的return new xQuery.prototype.init();這個只是調用了xQuery.prototype.init();這個引用的所對應的對象,其他的對象裡的屬性都沒管,也就是說代碼裡的:

size:function(){return this.length;}

還沒有被調用過,所以我們看到報了size is not a function的錯誤。呵呵,是不是被我說糊塗了啊,其實這裡我們還要瞭解一個javascript裡面的一個知識,javascript是一個指令碼語言,他和C、java在編譯,運行上有很大不同。javascript裡面如果我們定義一個function,例如:

var ftn = function(){     alert('Hello World');}

  頁面載入時候,瀏覽器裡面的javascript解譯器只是生命了ftn變數,這個過程叫做javasript的先行編譯,這時候的ftn = undefined,當我們new ftn();時候,也就是我們運行js代碼時候,javascript解譯器是先編譯再執行,而return new xQuery.prototype.init();只是運行了init()對象,而size還沒運行,所以運行結果就是size is not a function的錯誤。
  那麼要解決這個問題,我們只要在return new xQuery.prototype.init();時候同時讓xQuery.prototype其他代碼也運行起來,那麼上面的問題不是就解決了嗎?

  如是我做了第四個測試。

  測試四:

var xQuery = function(){return new xQuery.prototype.init();};xQuery.prototype = {init:function(){return this;},tempquery:'1.0.1',length:8,size:function(){return this.length;}};xQuery.prototype.init.prototype = xQuery.prototype;console.log(xQuery().tempquery);//1.0.1console.log(xQuery().length);//8console.log(xQuery() instanceof xQuery);//trueconsole.log(xQuery().size());//8

  哈哈,這不就是jQuery的效果啊。我把xQuery.prototype.init引用對應的對象的prototype原型鏈指向了xQuery.prototype,那麼構建 new xQuery.prototype.init();
時候xQuery.prototype 也同樣被構造了,那麼我在init裡面修改和init平級的屬性,效果如何了?

  測試五:

var xQuery = function(){return new xQuery.prototype.init();};xQuery.prototype = {init:function(){this.length = 10001;this.tempquery = '1.6.1';return this;},tempquery:'1.0.1',length:8,size:function(){return this.length;}};xQuery.prototype.init.prototype = xQuery.prototype;

結果:

console.log(xQuery().tempquery);//1.6.1console.log(xQuery().length);//10001console.log(xQuery() instanceof xQuery);//trueconsole.log(xQuery().size());//10001

  這就說明this指標指向的對象是同一個xQuery對象,表明xQuery.prototype也被構建了。不過上面的寫法似乎和jQuery的寫法還是有所不同,不過效果一樣了哈。

  jQuery裡面的jQuery.fn真是沒啥好說的,只是jQuery的開發人員覺得jQuery.prototype太長了為了節省代碼而將jQuery.fn作為jQuery.prototype的別名,下面我把代碼修改成jQuery的樣式,最終代碼如下:

var xQuery = function(){return new xQuery.prototype.init();};xQuery.fn = xQuery.prototype = {init:function(){this.length = 10001;this.tempquery = '1.6.1';return this;},tempquery:'1.0.1',length:8,size:function(){return this.length;}};xQuery.fn.init.prototype = xQuery.fn;console.log(xQuery().tempquery);//1.6.1console.log(xQuery().length);//10001console.log(xQuery() instanceof xQuery);//trueconsole.log(xQuery().size());//10001

  總結下吧:本來我想說這就是jQuery架構的核心,寫完後發現其實不然,所以這裡的總結只是說jQuery源碼裡的代碼技巧性很高,我下篇部落格打算暫停下分析jQuery源碼,而將一些基礎知識系統的講解下,javascript是一個常常讓人蒙掉的語言,就是它有很多非常規詭異的文法,或許這些大夥都清楚,但是時不時的溫故而知新還是相當有好處的。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.