关于读源码,读jQuery自然是不错,但太过于庞大不易解读,对于小白,最好从Zepto,Lodash这样的小库入手。

这里使用的是zepto1.1.6版本为例。

自执行函数

在阅读之前,先弄清楚闭包和自执行函数

两种方式: (function() {})() 和 (function() {}())

 (function() {
console.log('这里直接执行')
})()
 (function () {
console.log('这里直接执行')
}())

自执行函数的优势在于,避免了全局变量的污染,即在自执行函数体内声明的变量,外部是无法访问到的。

 (function () {
let val = '123'
})() console.log(val) // val is not defined

如需要获取变量val的值,只能在函数体内部返回,然后将函数赋值给一个全局变量

 let temp= (function () {
let val = '123';
return val; // 必须return, 否则获取不到值
})() window.temp = temp; console.log(temp) //

而关于闭包,简单理解就是在自执行函数内部声明变量或方法,在自执行函数内就形成了一个闭合的上下文环境,外部是无法直接访问的。

源码结构

 ;let Zepto = (function () {
let $, zepto = {}; return $; // 最终返回值
})() window.Zepto = Zepto;
window.$ === undefined && (window.$ = Zepto);

首先声明一个字支持函数并赋给变量Zepto, 再将变量Zepto赋给全局变量window.Zepto

如果$未被声明,则也将Zepto赋给window.$全局变量

此时,外部访问Zepto或者$都可以返回自执行函数内部的$(即 return $)

再看$到底是什么

$返回一个函数,传入的参数是selector选择器(即tagName,id,或className),context暂为空。

 ;let Zepto = (function () {
let $, zepto = {};
$ = function(selector, context) {
console.log('获取节点');
return zepto.init(selector, context);
};
return $;
})(); window.Zepto = Zepto;
window.$ === undefined && (window.$ = Zepto);

此时,如果访问节点, 会输出'获取节点'

 <div>
<span>测试</span>
<span>测试</span>
<span>测试</span>
</div>
 let span = $('span');
console.log(span)

这里报错是因为init方法还未定义;

继续创建 init方法

init函数是绑定在zepto对象上的方法(之前已经声明一个zepto空对象)

 zepto.init = function(selector, context) {
let dom;
// 处理dom的代码
return zepto.Z(dom, selector);
};

init处理dom部分,分为几种情况

1 . 当不传参数 $(), 直接返回zepto.Z()不传参

 if (!selector) return zepto.Z()

2 . 当传入字符串参数,又分为几种

 else if (typeof selector == 'string') {
selector = selector.trim() if (selector[0] == '<' && fragmentRE.test(selector))
dom = zepto.fragment(selector, RegExp.$1, context), selector = null else if (context !== undefined) return $(context).find(selector) else dom = zepto.qsa(document, selector) //这里的qsa其实就是document.querySelectorAll()
}

  (1) $(' span ')

  首先将清除字符串前后空格 selector.trim()

  (2) $('<div></div>')

  如果第一个字符是<,并且正则fragmentRE成立,

  则使用fragment方法处理dom节点

 if (selector[0] == '<' && fragmentRE.test(selector))
dom = zepto.fragment(selector, RegExp.$1, context), selector = null

  

  (3) $('span', 'div')

  如果传入第二个参数,即之前的context不等于undefined,则相当于执行$('div').find('span')

 else if (context !== undefined) return $(context).find(selector)

  若div中存在span则返回span,否则返回空数组。

(4)如以上三种不满足则执行最后一步,zepto.qsa()

3 . 如果传入函数,用document调用一个zepto对象,然后$.ready()方法, ready方法和上面的find方法一样在后面创建。

 else if (isFunction(selector)) return $(document).ready(selector);

4 . 若已经是一个zepto对象,则直接返回该对象,不必再调用$(), 即 $($('span')) === $('span')

 else if (zepto.isZ(selector)) return selector
 zepto.isZ = function(object) {
return object instanceof zepto.Z
}

5 . 若是引用类型

 else {
// 如参数是数组,则调用compact方法, 会将null或undefined剔除
if (isArray(selector)) dom = compact(selector)
// 如是DOM节点,则数组化
else if (isObject(selector))
dom = [selector], selector = null
// 以下和上面字符串参数的重复,何意未知。
else if (fragmentRE.test(selector))
dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null
//
//
else if (context !== undefined) return $(context).find(selector)
//
else dom = zepto.qsa(document, selector)
}

init是一个初始化方法,调用init时去执行zepto.Z()函数

 zepto.Z = function(dom, selector) {
dom = dom || []
dom.__proto__ = $.fn;
dom.selector = selector || '';
console.log(dom)
console.log(selector)
return dom;
};

关于Z()

1 . 传入dom,如果未传则返回[]空数组

  如果不传DOM节点 $(), 则返回一个空值。

  

2 . 如果有dom $('span'),则

3 . 同时在该数组的原型对象上创建$.fn对象

  在未定义$.fn之前,dom.__proto__原型对象上的方法是Array构造函数的内置方法

  

  而这里使用了dom.__proto__ = $.fn 重新定义了原型对象上的方法

 $.fn = {
get: function () {
console.log('自定义get方法')
},
on: function () {
console.log('自定义on方法')
}
}

  

可以看出,通过原型对象上创建新方法后,原来的内置方法都没有了。

如果只是想追加方法,则应该在原型对象上添加属性。

dom.__proto__.get = function() {}

dom.__proto__.on = function() {}

  

4 . 最后返回该DOM节点对象。此时$('span')对象就可以调用方法get和on了。

Zepto源码分析之一(代码结构及初始化)的更多相关文章

  1. Vue.js 源码分析(一) 代码结构

    关于Vue vue是一个兴起的前端js库,是一个精简的MVVM.MVVM模式是由经典的软件架构MVC衍生来的,当View(视图层)变化时,会自动更新到ViewModel(视图模型),反之亦然,View ...

  2. jQuery 源码分析(一) 代码结构

    jQuery是一个Javascript库,它支持链式操作方式,即对发生在同一个JQuery对象上的一组动作,可以直接接连写无需要重复获取对象.这一特点使得JQuery的代码无比优雅,而且有强大的选择器 ...

  3. Zepto源码分析(一)核心代码分析

    本文只分析核心的部分代码,并且在这部分代码有删减,但是不影响代码的正常运行. 目录 * 用闭包封装Zepto * 开始处理细节 * 正式处理数据(获取选择器选择的DOM) * 正式处理数据(添加DOM ...

  4. 一个普通的 Zepto 源码分析(二) - ajax 模块

    一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...

  5. Zepto源码分析(二)奇淫技巧总结

    Zepto源码分析(一)核心代码分析 Zepto源码分析(二)奇淫技巧总结 目录 * 前言 * 短路操作符 * 参数重载(参数个数重载) * 参数重载(参数类型重载) * CSS操作 * 获取属性值的 ...

  6. MySQL源码分析以及目录结构 2

    原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...

  7. MySQL源码分析以及目录结构

    原文地址:MySQL源码分析以及目录结构作者:jacky民工 主要模块及数据流经过多年的发展,mysql的主要模块已经稳定,基本不会有大的修改.本文将对MySQL的整体架构及重要目录进行讲述. 源码结 ...

  8. 一个普通的 Zepto 源码分析(三) - event 模块

    一个普通的 Zepto 源码分析(三) - event 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块, ...

  9. 一个普通的 Zepto 源码分析(一) - ie 与 form 模块

    一个普通的 Zepto 源码分析(一) - ie 与 form 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核 ...

  10. ffplay源码分析2-数据结构

    ffplay是FFmpeg工程自带的简单播放器,使用FFmpeg提供的解码器和SDL库进行视频播放.本文基于FFmpeg工程4.1版本进行分析,其中ffplay源码清单如下: https://gith ...

随机推荐

  1. jquery动态添加的元素不能直接应用事件方法的时候

    对于由 jQuery 动态生成的元素,如用 jQuery 给元素添加 class,或者直接添加一对 p 标签,不能直接绑定常用的事件,如 click.因为这些元素属于动态生成,除非采用 onclick ...

  2. PID控制算法的简单分析和仿真!

    PID算法简单剖析如下: 1.首先我们来看一下PID系统的基本组成模块: 如图所示,图中相关参数的表示如下: r(t):系统实际上需要的输出值,这是一个标准值,在我们设定了之后让这个系统去逼近的一个值 ...

  3. B. Nirvana Codeforces Round #549 (Div. 2) (递归dfs)

    ---恢复内容开始--- Kurt reaches nirvana when he finds the product of all the digits of some positive integ ...

  4. XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix

    A. Artifacts 建立语法分析树,首先根据上下界判断是否有解,然后将所有数按下界填充,线段树判断是否存在和超过$K$的子区间. B. Brackets and Dots 最优解中一定包含一对中 ...

  5. css加载动画...

    加载动画... <p>加载动画...</p> <p> </p> <p> </p> <style><!-- .c ...

  6. Tornado-基于正则的路由和动态分页

    概览 这一小节涉及了三部分内容: 1.动态分页设计 2.基本的路由系统以及基于正则的路由 3.模块引擎的继承和导入 4.web项目文件夹和ReuquestHandler的分类 5.跨站脚本攻击 文件结 ...

  7. (51)Wangdao.com第七天_JavaScript 编写位置及输出语句

    JavaScript 编写位置 编写在html内部标签的属性中 不推荐使用,因为结构和行为耦合,不便于维护 主要有  <button onclick="alert('点我干哈!');& ...

  8. React 面向组件化编程 - 封装了webpack - npm run build 产生的包的 /static 引用路径问题

    React 面向组件化编程 面向对象 ----> 面向模块 ----> 面向组件 套路: 注意: 组件名必须大写开头: 只能有一个根标签: <input />虚拟DOM 元素必 ...

  9. php抓取图片进行内容提取解析,文字性pdf进行内容文字提取解析

    2018年7月7日18:52:17 php是用纯算法,自己是提取图片内容不是不行,可以但是优化起来很麻烦还得设计学习库,去矫正数据的正确率 对于大多数项目来说,如果不是做ocr服务,就不必要做需求工具 ...

  10. String工具类2

    1:比较字符串 public static void main(String[] args) { // String去创建对象有多种方式 // 方式1 直接字面值赋值 String s = " ...