從Console中看看jQuery的原型鏈

寫在最前

這不是一篇分析源碼的文章——因為作者也沒有怎么看源碼。本文主要分析jQuery中到底是如何進行構(gòu)造原型鏈的。思路是通過逆推來拋出問題再用正推的方式來分析解決問題。歡迎關(guān)注作者博客,不定期更新中——

jQuery是什么

首先你知道jQuery有兩種使用方法吧?
一種是jQuery('#xxx');一種是new jQuery('#xxx');
這兩種方式都會返回一個實例。其原型鏈應該有一大堆方法。比如:jQuery('#xxx').css;jQuery('#xxx').attr;jQuery('#xxx').html...等等。
并且我們應該認識到jQuery這個函數(shù)一方面返回了一個實例,另一方面其本身也是構(gòu)造函數(shù)(因為 new jQuery),那么其原型鏈也應該指向了那一大堆方法。我們一步步打印一下來驗證下猜測:

console.log(jQuery) // 來看下jQuery函數(shù)體
function ( selector, context ) {

    // The jQuery object is actually just the init constructor 'enhanced'
    // Need init if jQuery is called (just allow error to be thrown if not included)
    return new jQuery.fn.init( selector, context );
  } //小技巧,可以引入沒有壓縮過的jQuery進行學習,這樣備注,變量名會抱持原樣。

好的果然沒猜錯,我們看到了一個構(gòu)造函數(shù)為jQuery.fn.init。通過new這個構(gòu)造函數(shù)就可以采用第一種jQuery()的形式來生成實例。接下來驗證下jQuery.fn.init的prototype屬性上是不是有我們猜測的一大堆方法。

console.log(Object.keys(jQuery.fn.init.prototype))
// ["jquery","constructor","init","show","hide","toggle","on","one", "off","detach","remove","text","append", ...]

從結(jié)果中也可以知道我們的推測是正確的。在jQuery.fn.init的prototype中有著封裝的方法可供實例調(diào)用。

new jQuery('#xxx')

驗證了無new構(gòu)造實例的形式之后再來看下對于jQuery同時應該是個構(gòu)造函數(shù)的猜測。

console.log(Object.keys(jQuery.prototype))
//["jquery","constructor","init","show","hide","toggle","on","one", "off","detach","remove","text","append", ...]
console.log(jQuery.prototype === jQuery.fn.init.prototype) //true

可以看出jQuery也確實是一個構(gòu)造函數(shù)其prototype和jQuery.fn.init的一樣都指向了那一大堆方法。

init方法

讓我們再看下這段代碼:

function ( selector, context ) {

    // The jQuery object is actually just the init constructor 'enhanced'
    // Need init if jQuery is called (just allow error to be thrown if not included)
    return new jQuery.fn.init( selector, context );
  }

這里面返回的構(gòu)造函數(shù)jQuery.fn.init我們可以看成是調(diào)用了jQuery.fn的init方法。同時細心的同學們應該可以觀察到,在jQuery.fn.init.prototype中也有個方法叫init!。那么是不是。。讓我們打印一下我們的猜測:

console.log(jQuery.fn.init.prototype.init === jQuery.fn.init) //true

發(fā)現(xiàn)了么同學們!既然jQuery.fn可以調(diào)用jQuery.fn.init其原型鏈上的方法,那么一定有:

jQuery.fn.init.prototype === jQuery.fn // true

小結(jié)

好的現(xiàn)在大家可能有種似懂非懂的感覺?來看下面這張圖來總結(jié)下我們的發(fā)現(xiàn)。


通過前文加上我們上圖的展示,原型鏈的關(guān)系已經(jīng)很明了了。在原型鏈上綁定了很多很多方法確定無疑。與此同時有三個東西指向了該原型鏈即:

jQuery.fn === jQuery.fn.init.prototype //true
jQuery.fn.init.prototype === jQuery.prototype //true

在完成這三個的指向之后就可以滿足我們起初的需求:

  • 調(diào)用jQuery()可以返回一個實例
  • jQuery自己也是構(gòu)造函數(shù)可以被顯式new來構(gòu)建實例
  • 實例的方法綁定在了原型鏈上

當然了jQuery里面還有方法是綁定在jQuery本身的,綁定在原型鏈上的方法通過jQuery('#xxx').xxx調(diào)用,這個是相對某個元素的方法,綁定在jQuery本身的方法通過$.xxx調(diào)用,這個是某種特定的靜態(tài)方法。我們現(xiàn)在只是討論基礎的jQuery在最外層構(gòu)建時這些prototype屬性都是怎么關(guān)聯(lián)的。想深入了解的歡迎去讀源碼——

正向梳理一遍

再回過頭來看上文提到的三個需求:

  • 調(diào)用jQuery()可以返回一個實例
  • jQuery自己是構(gòu)造函數(shù)可以被顯式new來構(gòu)建實例
  • 實例的方法綁定在了原型鏈上

如果讓你來寫一個你怎么寫?ok,我們一步一步來

調(diào)用jQuery()可以返回一個實例

//v1.0
var j = function(selector){
  return new init(selector); 
}
var init = function() {...}

返回的這個實例可以調(diào)用原型鏈方法

//v2.0
//即fn.init的原型應該是j.prototype
var fn = {}
var xxx = function() {}
fn.init = function(selector) {console.log(selector)}
var j = function(selector){
  return new fn.init(selector); 
}
xxx.prototype = {
    setColor: function(color){console.log(color)}
    ...
}
fn.init.prototype = xxx.prototype
var a = new j(1) //1
a.setColor('red') // red

init方法也要從原型鏈上調(diào)用

//v3.0
var xxx = function() {}
var j = function(selector){
  return new j.fn.init(selector); //借用j.fn來找到原型鏈方法,不然找不到
}
j.fn = xxx.prototype = { //j本身是構(gòu)造函數(shù)
  init: function(selector) {
    console.log(selector)
  },
  setColor: function(color) {
    console.log('setColor:' + color)
  }
}
j.fn.init.prototype = j.fn
var a = new j(1)
a.setColor('red')

jQuery自己是構(gòu)造函數(shù)可以被顯式new來構(gòu)建實例

//v3.0
//將xxx替換為j,那么j當做構(gòu)造函數(shù)后其原型鏈也指向了那一堆方法
var j = function(selector){
  return new j.fn.init(selector); //借用j.fn來找到原型鏈方法,不然找不到
}
j.fn = j.prototype = { //j本身是構(gòu)造函數(shù)
  init: function(selector) {
    console.log(selector)
  },
  setColor: function(color) {
    console.log('setColor:' + color)
  }
}
j.fn.init.prototype = j.fn
var a = new j(1)
a.setColor('red')

至此我們便寫好了一個jQuery初級版原型鏈的一個構(gòu)建。里面很多操作更多的是為了讓暴露的變量盡可能的少,所以在原型鏈構(gòu)件上有一種循環(huán)賦值的趕腳哈哈哈。有興趣的同學可以繼續(xù)研究。

最后

慣例po作者的博客,不定時更新中——
有問題歡迎在issues下交流,捂臉求star=。=

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 工廠模式類似于現(xiàn)實生活中的工廠可以產(chǎn)生大量相似的商品,去做同樣的事情,實現(xiàn)同樣的效果;這時候需要使用工廠模式。簡單...
    舟漁行舟閱讀 8,130評論 2 17
  • 1,javascript 基礎知識 Array對象 Array對象屬性 Arrray對象方法 Date對象 Dat...
    Yuann閱讀 1,153評論 0 1
  • 在線閱讀 http://interview.poetries.top[http://interview.poetr...
    前端進階之旅閱讀 115,556評論 24 450
  • 剛剛成年的時候我進了大學,我說的只是時間,那時候我并沒有具備成年主要表現(xiàn)在閱歷孤陋,僅僅是到了年齡。 高中畢業(yè)那會...
    麻花可樂閱讀 250評論 0 0
  • 兩個小時翻完,有點對不起李開復辛苦的著作,一碗好雞湯啊。在疾病面前我們都很無助,我是懼怕疾病的,不敢去面對,不知道...
    司馬靜塵閱讀 255評論 0 0

友情鏈接更多精彩內(nèi)容