天天看点

读Zepto源码之代码结构

虽然最近工作中没有怎么用 zepto ,但是据说 zepto 的源码比较简单,而且网上的资料也比较多,所以我就挑了 zepto 下手,希望能为以后阅读其他框架的源码打下基础吧。

本文阅读的源码为 zepto1.2.0

阅读zepto之前需要了解 javascript 原型链和闭包的知识,推荐阅读王福朋的这篇文章:深入理解 Javascript 原型和闭包,写得很详细,也非常易于阅读。

如果在编辑器中将 zepto 的源码折叠起来,看到的就跟上面的代码一样。

zepto 的核心是一个闭包,加载完毕后立即执行。然后暴露给全局变量 <code>zepto</code> ,如果 <code>$</code> 没有定义,也将 <code>$</code> 赋值为 <code>zepto</code> 。

在这部分中,我们先不关注 zepto 的具体实现,只看核心的结构,因此我将zepto中的逻辑先移除,得出如下的核心结构:

在源码中,可以看出, <code>$</code> 其实是一个函数,同时在 <code>$</code> 身上又挂了很多属性和方法(这里体现在 <code>$.fn</code> 身上,其他的会在后续的文章中谈到)。

我们在使用 zepto 的时候,会用 <code>$</code> 去获取 <code>dom</code> ,并且在这些 <code>dom</code> 对象身上都有 zepto 定义的各种各样的操作方法。

从上面的伪代码中,可以看到,<code>$</code> 其实调用了 <code>zepto.init()</code> 方法,在 <code>init</code> 方法中,会获取到 <code>dom</code> 元素集合,然后将集合交由 <code>zepto.Z()</code> 方法处理,而 <code>zepto.Z</code> 方法返回的是函数 <code>Z</code> 的一个实例。

函数 <code>Z</code> 会将 <code>doms</code> 展开,变成实例的属性,<code>key</code> 为对应 <code>domObj</code> 的索引, 并且设置实例的 <code>length</code> 属性。

读到这里,你可能会有点疑惑,<code>$</code> 最终返回的是 <code>Z</code> 函数的实例,但是 <code>Z</code> 函数明明没有 <code>dom</code> 的操作方法啊,这些操作方法都定义在 <code>$.fn</code> 身上,为什么 <code>$</code> 可以调用这些方法呢?

其实关键在于这句代码 <code>Z.prototype = $.fn</code> ,这句代码将 <code>Z</code> 的 <code>prototype</code> 指向 <code>$.fn</code> ,这样,<code>Z</code> 的实例就继承了 <code>$.fn</code> 的方法。

既然这样就已经让 <code>Z</code> 的实例继承了 <code>$.fn</code> 的方法,那 <code>zepto.Z.prototype = $.fn</code> 又是为什么呢?

如果我们再看源码,会发现有这样的一个方法:

这个方法是用来判读一个对象是否为 zepto 对象,这是通过判断这个对象是否为 <code>zepto.Z</code> 的实例来完成的,因此需要将 <code>zepto.Z</code> 和 <code>Z</code> 的 <code>prototype</code> 指向同一个对象。 <code>isZ</code> 方法会在 <code>init</code> 中用到,后面也会介绍。

zepto源码分析-代码结构

zepto对象思想与源码分析

zepto设计和源码分析

zepto源码中关于<code>zepto.Z.prototype = $.fn</code>的问题