虽然最近工作中没有怎么用 zepto , 但是据说 zepto 的源码比较简单, 而且网上的资料也比较多, 所以我就挑了 zepto 下手, 希望能为以后阅读其他框架的源码打下基础吧.
源码版本
本文阅读的源码为 zepto1.2.0 https://github.com/madrobby/zepto/tree/v1.2.0
源码结构
整体结构
- var Zepto = (function(){
- ...
- })()
- window.Zepto = Zepto
- window.$ === undefined && (window.$ = Zepto)
如果在编辑器中将 zepto 的源码折叠起来, 看到的就跟上面的代码一样.
zepto 的核心是一个闭包, 加载完毕后立即执行, 然后暴露给全局变量 zepto , 如果全局 $ 没有定义, 也将 $ 赋值为 Zepto
核心结构
在这部分中, 我们先不关注 zepto 的具体实现, 只看核心的结构, 因此我将 zepto 中的逻辑先移除, 得出如下的核心结构:
- var zepto = {}, $
- function Z(doms) {
- var len = doms.length;
- for(var i = 0; i < len; i++) {
- this[i] = doms[i];
- }
- this.length = len;
- }
- zepto.Z = function(doms) {
- return new Z(doms)
- }
- zepto.init = function(doms) {
- var doms = ['dom1','dom2','dom3']
- return zepto.Z(doms)
- }
- $ = function() {
- return zepto.init()
- }
- $.fn = {
- constructor: zepto.Z,
- method: function(){
- return this
- }
- ...
- }
zepto.Z.prototype = Z.prototype = $.fn
return $
在源码中, 可以看出, $ 其实是一个函数, 同时在 $ 身上又挂了很多属性和方法 (这里体现在 $.fn 身上, 其他的会在后续的文章中谈到).
我们在使用 zepto 的时候, 会用 $ 去获取 dom, 并且在这些 dom 对象上都有 zepto 定义的各种各样的操作方法.
从上面的伪代码中, 可以看到,$ 其实调用了 zepto.init() 方法, 在 init 方法中, 会获取到 dom 元素集合, 然后将集合交由 zepto.Z() 方法处理, 而 zepto.Z 方法返回的是函数 Z 的一个实例.
函数 Z 会将 doms 展开, 变成实例的属性, key 为对应 dom 的索引, 并且设置实例的 length 属性.
zepto.Z.prototype = Z.prototype = $.fn
读到这里, 你可能会有点疑惑,$ 最终返回的是 Z 函数的实例, 但是 Z 函数明明没有 dom 的操作方法啊, 其实这些操作方法都定义在 $.fn 身上, 为什么 $ 可以调用这些方法呢?
其实关键在于这句代码 Z.prototype = $.fn, 这句代码将 Z 的 prototype 指向 $.fn, 这样 Z 的实例就继承了 $.fn 的方法. 这一块知识可以去看一下高程 3 中的原型那一章节内容.
既然这样就已经让 Z 的实例继承了 $.fn 的方法, 那
zepto.Z.prototype = $.fn
又是为什么呢?
如果我们再看源码, 会发现有这样的一个方法:
- zepto.isZ = function(object) {
- return object instanceof zepto.Z
- }
这个方法是用来判读一个对象是否为 zepto 对象, 这是通过判断这个对象是否为 zepto.Z 的实例来完成的, 因此需要将 zepto.Z 和 Z 的 prototype 指向同一个对象. isZ 方法会在 init 中用到, 后面也会介绍.
来源: https://www.cnblogs.com/zhouyangla/p/9196970.html