關於 Zepto 源碼結構分析的文章已經不少了,本文主要從兩點,即圖示和詳細步驟跟蹤上,對其進行分析。javascript
首先仍是上源碼:html
var Zepto = (function() {
})()
window.Zepto = Zepto
window.$ === undefined && (window.$ = Zepto)
複製代碼
外層結構很簡單,無非是執行一個當即執行函數,把返回結構賦給 Zepto
,再把 Zepto
綁定到全局。最後,若是全局的美圓符號 $
沒有被佔用,則把 Zepto
賦給 $
。不少文章裏都已經討論過了,再也不細說。java
var zepto = {}, $
function Z(doms) {
var len = doms.length
for (var i = 0; i < len; i++) {
this[i] = doms[i]
}
this.length = doms.length
}
zepto.fragment = function(html, name, properties) {
// 根據 html 字符串生成 dom
}
zepto.isZ = function(object) { return object instanceof zepto.Z}
zepto.Z = function(doms) {
return new Z(doms)
}
zepto.init = function(selector, context) {
var dom
// 根據 selector 生成 dom
// ···
return zepto.Z(dom, selector)}
$ = function(selector, context){
return zepto.init(selector, context)
}
zepto.qsa = function(element, selector){
// 根據 選擇器字符串生成 dom
}
$.type = type
······
// 把各類工具方法綁定到 $ 上
$.fn = { constructor: zepto.Z,
forEach: emptyArray.forEach ······
// 把各類實例方法綁定到 $.fn 上
}
zepto.Z.prototype = Z.prototype = $.fn
$.zepto = zepto
return $複製代碼
以上代碼是抽取主要部分後獲得的骨幹,饒是如此,結構就已經很複雜了。對象和原型之間互相賦值和引用,函數之間互相調用,楞一遍看下來讓人很是暈。數組
咱們如今就來整理一下。dom
首先,這裏有三個最主要的對象,這三個對象就是:函數
$
, zepto
, Z
。注意,這裏的 zepto
首字母是小寫,不要和外層結構的 Zepto
搞混了。工具
下面就對這三者之間的關係進行分析。ui
仔細看源碼,分析三者以及它們之間的關係,咱們發現如下幾個事實:this
$
,也就是說其實就是 $
被賦給了外層的 Zepto
。$
自己是一個函數,它調用了 zepto.init
方法 並返回。zepto.init
函數作了不少操做,其中最後一步調用了 zepto.Z
。Z
是一個構造函數。zepto.Z
方法調用構造函數 Z
,返回一個 Z
的實例。zepto
對象被賦給了 $.zepto
屬性。$.fn
被賦給了 zepto.Z
和 Z
的原型。也就是說後二者的原型就是 $.fn
。結合圖例仔細看幾遍,$
, zepto
, Z
, zepto.Z
, zepto.init
, $.fn
之間的關係應該就清晰多了。spa
至於圖中出現的 zepto.qsa
和 zepto.fragment
,那是在 zepto.init
方法中被調用的重要方法,因此一併也畫進去了,對總體結構沒有影響。
雖然知道了源碼內部三個主要對象的關係,可是源碼又是如何起做用的呢?
咱們知道,Zepto 使用時都是以選擇器爲開端的。當咱們使用 $()
來生成一個 Zepto 對象時,內部究竟發生了什麼?如今咱們就從源碼入手開始分析。
$
方法,內部調用 zepto.init
方法。zepto.init
方法。該方法判斷傳入的 selector
參數的類型,對其作相應的處理。zepto.fragment
方法。zepto.qsa
方法。selector
參數是其餘類型時(對象、數組、Zepto 實例、函數······),作其餘的相應處理。zepto.Z(dom, selector)
對生成的 dom 作一層包裹。zepto.Z
方法。該方法經過 new Z(dom, selector)
來生成一個 Z
的實例並返回。Z
。Z
的內部很簡單,僅僅是對傳入的 dom 作一個簡單的循環拷貝,並複製了它的 length
,生成了一個類數組對象。這個對象就是一開始 $()
方法最終返回的對象。至此,通過層層遞進的分析,咱們獲得告終論:$()
返回的就是一個 Z
的實例。
前面代碼的倒數第三行有 zepto.Z.prototype = Z.prototype = $.fn
。這行代碼很是重要,它讓 Z
的 prototype
指向了 $.fn
,這也是爲何 Z
的實例能夠調用 $.fn
中的一大堆方法。
至於這個等式的前半部分,zepto.Z.prototype = Z.prototype
,大概是因爲 $.fn
的 constructor
被指給了zepto.Z
。爲了讓 $() instanceof Zepto.zepto.Z
成立,因此纔有這一等式。
不過,我認爲這多少有點違揹人的直覺,也許讓 $.fn
的 constructor
指向 $
自己更好。畢竟在 jQuery 中,$() instanceof jQuery === true
,可是在 Zepto 中,$() instanceof Zepto === false
。
至於這個設計的優劣,又是另外一個話題了,你們能夠討論。