3

为什么要看zepto源码

js相当于造房子的砖头,而Vue,react...则是人家造好了的轮子。在工作中一直用的是人家造好的轮子,大家都知道的是前端中轮子变化是很快的,但js是‘不会变的’。所以只有自己会造轮子了才能在前端这条道路上走得更远。并且,个人觉得读完源码后:真正留在自己脑子里的,是框架的设计思想。总之,一直觉得js和设计思想在前端中是最最最最重要的。

需要先了解一下原型和原型链的相关知识

1.每个函数都有一个prototype属性,无论是自定义的还是系统内置的
2.所以通过函数new出来的东西,这个东西都有一个__proto__指向这个函数的prototype
3.当你想要使用一个对象(或一个数组)的某个功能时:如果该对象本身具有这个功能,则直接使用,如果没有就去__proto__中找

怎么读zepto源码

解读zepto的设计

cmd-markdown-logo
上面这张图解析:arr具有push属性,因此可以直接使用。但是arr不具备lzzhyAddName属性,因此需要通过arr._proto = {lzzhyAddName: function(){console.log('my name is lzzhy')}}来添加这个属性后才能用。

流程图解析:
cmd-markdown-logo

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函数了。

函数如下:

cmd-markdown-logo

我们可以看到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函数了。

cmd-markdown-logo

其中dom指的是数组,$.fn指的是一个包含很多属性的一个对象{......}
371行:把数组或者空数组赋值给 dom
372行:把$.fn赋值给dom._proto隐私原型
373行:把字符串或者空字符串赋值给 dom.selector

下图是$.fn函数部分截图:
cmd-markdown-logo

  • 其中774-779行相对应的':'后的可以转换(如:emptyArray.forEach相当于[].forEach又相当于Array.prototype.forEach);
  • 其中map,slice,ready...函数都是重新定义的,也就是官方文档中我们用到的那些对象函数API如:

cmd-markdown-logo

总结

以上整个分析过程是从大到小将一个个函数分割出来,其中解读了比较重要的几个函数。

源码分析到这里了,那么就用一个简单的代码结构对之前的做个总结。并且根据这个结构,将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)

cmd-markdown-logo

大致就是这张图的流程,最后的dom是挂载在$.fn上。dom._proto = $.fn

更多请参考我的博客


lzzhy
34 声望11 粉丝