zepto源码分析
前言
想比10000多行的jQuery,zepto可谓是短小精悍,作为主要应用在移动端的低配版jQuery,源代码只有大概1500行,代码很容易理解,也写的很巧妙。有可以借鉴的东西。
最外层的闭包
最外层是一个立即执行的函数
(function(global, factory) {
if (typeof define === 'function' && define.amd)
define(function() { return factory(global) })
else
factory(global)
}(this, function(window){
var Zepto = (function(){
//代码写在这里面
var zepto = {}; //zepto是一个空对象
var $;
...
$.zepto = zepto;
return $
})
window.Zepto = Zepto;
window.$ === undefined && (window.$ = Zepto);
}))
最后把$和Zepto作为属性挂在了window对象上,对外部只有$使用,不会污染全局环境。
zepto对象
重点要说一下zepto这个对象,这个对象很重要,贯穿始终。需要注意的是,zepto就是一个对象,而jquery里边是一个类。这是不一样的地方。一些方法会挂在zepto对象上。比如Z()这个方法,一会会重点说。
关于$的解读
接下来说的是zepto中的对象$.
$ = function(selector, context){
return zepto.init(selector, context)
}
$是一个很重要的函数,接收两个参数,selector选择器,和context(可选的)。$也是定于在Zepto函数中,我们看他的代码实际上发现,调用$的时候,其实是调用了zepto对象上的init方法,那么这个init方法又是个什么东西呢?
zepto.init()
init这个方法里边有点复杂。
zepto.init = function(selector, context) {
var dom
//如果没有传递参数,返回一个空对象。
if (!selector) return zepto.Z()
// 如果selector是一个字符串(css选择器)
else if (typeof selector == 'string') {
//去掉前后空格
selector = selector.trim()
// 如果是<xx>这样的html代码
if (selector[0] == '<' && fragmentRE.test(selector))
dom = zepto.fragment(selector, RegExp.$1, context),
selector = null
// 如果有context参数,则在上下文中寻找selector
else if (context !== undefined) return $(context).find(selector)
// 如果是一个css表达式,通过qsa方法来寻找元素
else dom = zepto.qsa(document, selector)
}
//如果是一个方法,在ready的时候加载它
else if (isFunction(selector)) return $(document).ready(selector)
// 如果是zepto对象,返回自身
else if (zepto.isZ(selector)) return selector
else {
// 如果是一个数组,
if (isArray(selector)) dom = compact(selector)
// 如果是一个对象,转成一个数组
else if (isObject(selector))
dom = [selector], selector = null
// 如果是一个html代码,创建之。
else if (fragmentRE.test(selector))
dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
// 如果上下文参数不为空,跟上边一样
else if (context !== undefined) return $(context).find(selector)
// 否则在document查找selector
else dom = zepto.qsa(document, selector)
}
// 经过一系列判断来适配不同的情况,反正是有dom了。
return zepto.Z(dom, selector)
}
前边经过各种判断,init最后会返回zepto对象的Z方法,那个Z方法看名字应该是类似于构造函数之类的。看一下Z的代码。
zepto.Z()
zepto.Z = function(dom, selector) {
return new Z(dom, selector)
}
好吧,这个方法返回了一个Z对象,我们知道用new创建的对象需要构造函数,接下来自然我们要看一下构造函数Z了。
function Z
function Z(dom, selector) {
var i, len = dom ? dom.length : 0
for (i = 0; i < len; i++) this[i] = dom[i]
this.length = len
this.selector = selector || ''
}
好了,看到这里,暂时告一段落,我们来分析一波。我们调用$(selector,context)这个方法,经过zepto.init(selector,context)--->zepto.Z(dom,selector)----->new Z(dom,selector).
最后生成一个Z的实例,这个实例有个length属性,代表dom的长度。
既然如此,那么我们是如何在Z这个实例上调用那些各种方法,比如addClass()这类的方法。
$.fn
在zepto中$.fn()是一个简简单单的对象。这个对象是一个空对象。而那些操作dom的方法都是写在这个对象里边。我们大概看一下这个对象。
$.fn = {
constructor: zepto.Z,
length:0,
map:function(){...},
addClass:function(){...},
remove:function(){...}
....
}
//接下来很重要
zepto.Z.prototype = Z.prototype = $.fn
重要的事情说三遍
zepto.Z.prototype = Z.prototype = $.fn
zepto.Z.prototype = Z.prototype = $.fn
zepto.Z.prototype = Z.prototype = $.fn
其实很简单,把$.fn这个对象挂在了Z的原型对象上,那么new Z()出来的实例就都能访问$.fn上面定义的属性了,所以也就能执行各种dom操作。
至此,zepto的精髓基本讲的差不多了。大概用了1000行代码实现了这个过程,接下来的代码基本是分析了一些事件的问题还有ajax相关的东西。暂且不说了。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。