关于 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
。
至于这个设计的优劣,又是另外一个话题了,你们能够讨论。