为什么要看zepto源码
js相当于造房子的砖头,而Vue,react...则是人家造好了的轮子。在工作中一直用的是人家造好的轮子,大家都知道的是前端中轮子变化是很快的,但js是‘不会变的’。所以只有自己会造轮子了才能在前端这条道路上走得更远。并且,个人觉得读完源码后:真正留在自己脑子里的,是框架的设计思想。总之,一直觉得js和设计思想在前端中是最最最最重要的。
需要先了解一下原型和原型链的相关知识
1.每个函数都有一个prototype属性,无论是自定义的还是系统内置的
2.所以通过函数new出来的东西,这个东西都有一个__proto__指向这个函数的prototype
3.当你想要使用一个对象(或一个数组)的某个功能时:如果该对象本身具有这个功能,则直接使用,如果没有就去__proto__中找
怎么读zepto源码
解读zepto的设计
上面这张图解析:arr具有push属性,因此可以直接使用。但是arr不具备lzzhyAddName属性,因此需要通过arr._proto = {lzzhyAddName: function(){console.log('my name is lzzhy')}}来添加这个属性后才能用。
流程图解析:
PS:源码在设计的时候并不像上面代码那样简单只不过原理是一样的,源码具体实现方式还是得边读边理解。
zepto源码结构
第一步,先整个悦读源码,从大到小以宏观看微观的想法。因此,先将整个大体的结构弄懂:
总结来说,整个结构可以简单抽离成这样:
var zepto = (function(){
var $, zepto = {}
// ...省略N行代码
$ = function(selector,context) {
return zepto.init(selector,context)
}
// ...省略N行代码
return $
})()
window.zepto = zepto
window.$ === undefined && (window.$ = zepto)
在这里我们可以看到:平常我们$('p')使用zepto的时候,最终会顺藤摸瓜到 $ = function(selector,context) {}这个函数中(其中内容在这一步可不深究),而p选择器也会传递给selector参数。因此经过剥离之后,我们发现下一步需要探究的是$ = function(selector,context) {return zepto.init(selector,context)} 这个函数return出来的zepto.init函数
zepto.init函数
在上一步“zepto源码结构”中我们已经剖析到zepto.init函数了。
函数如下:
我们可以看到zepto.init函数大约有几十行,把中间那if...else...操作去掉(其中大致分为四种情况),剩下的就是:
zepto.init = function(selector, context) {
var dom
// ...此处省略N行...
// 分情况对dom赋值:
// 1.selector为空
// 2.selector是字符串,其中又分好几种情况
// 3.selector是函数
// 4.其他情况,如selector是数组、对象等
return zepto.Z(dom,elector)
}
在这个函数中,if...else...判断之后,最终 return到zepto.Z函数
zepto.Z函数
在上一步“zepto.init函数”中我们已经剖析到zepto.Z函数了。
其中dom指的是数组,$.fn指的是一个包含很多属性的一个对象{......}
371行:把数组或者空数组赋值给 dom
372行:把$.fn赋值给dom._proto隐私原型
373行:把字符串或者空字符串赋值给 dom.selector
下图是$.fn函数部分截图:
- 其中774-779行相对应的':'后的可以转换(如:emptyArray.forEach相当于[].forEach又相当于Array.prototype.forEach);
- 其中map,slice,ready...函数都是重新定义的,也就是官方文档中我们用到的那些对象函数API如:
总结
以上整个分析过程是从大到小将一个个函数分割出来,其中解读了比较重要的几个函数。
源码分析到这里了,那么就用一个简单的代码结构对之前的做个总结。并且根据这个结构,将zepto的初始对象的过程在捋一捋。
var zepto = (function(){
var $, zepto = {}
// ...省略N行代码
zepto.Z = function(dom,selector){
dom = dom || []
dom._proto = $.fn
dom.selector = selector || ''
return dom
}
$ = function(selector,context) {
return zepto.init(selector,context)
}
// ...省略N行代码
zepto.init = function(selector, context) {
var dom
// ...针对不同情况分别赋值
return zepto.Z(dom,elector)
}
$.fn = {
// 里面N个重新定义的zepto的API
}
return $
})()
window.zepto = zepto
window.$ === undefined && (window.$ = zepto)
大致就是这张图的流程,最后的dom是挂载在$.fn上。dom._proto = $.fn
更多请参考我的博客
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。