jQuery2.x源码解析(构建篇)
笔者阅读了园友艾伦 Aaron的系列博客《jQuery源码分析系列》,跑艾伦的部分代码后,感觉仍然不够解渴,对jQuery依旧一知半解,产生了很多问题。阅读源码博客已经无法解决这些问题,所以笔者决定亲自查看jQuery源码,解除心中的疑问。阅读的形式属于自问自答,笔者会提出疑问,然后亲自解答(吐槽:感觉有点像一休哥和将军大人>_<)。
问题的来源主要有3种:
1.在阅读园友艾伦博客后产生的疑问
2.以前就有疑问,艾伦博客却没有解答或者解释不够明白
3.阅读源码的过程中产生的疑问
所以这个jQuery源码解析系列并非教程,而是笔者的学习jQuery源码的笔记,因此才会采取问答这种不系统的形式。如果大家想系统学习jQuery源码,还请仔细阅读艾伦 Aaron的博客;或是直接阅读jQuery在gitbub上的源码(目前的master版本是2.2-stable,笔者阅读的也是这个版本的代码)。如果在阅读后也和笔者一样,对一些内容存在疑问,可以看看笔者的系列博客,看看你有没有你疑惑的问题;如果没有就发问给我,我们一起思考答案。
提问:如何构建jQuery的源码
在我开始阅读jQuery的源码时,发现源代码本身是有模块化的,而艾伦 Aaron阅读的版本没有,他是直接阅读的dist后的代码。那么jQuery是如何构建源代码的呢?
答:阅读jQuery在github上的README.md文件,里面已经说得非常清楚了。先安装git客户端和nodejs及npm。然后将github上的资源克隆到本地,找一个目录,然后打开命令行,输入git的clone命令:
git clone git://github.com/jquery/jquery.git
本地就会克隆出jQuery的源代码:

然后进入该目录下,在命令行上运行如下命令,jQuery就会自动安装npm模块,并构建jQuery了。
npm run build
最后在dist目录中,会构建出我们想要的jQuery文件了。
提问:git上的jQuery目录结构是怎样的
答:具体目录结构可以看上图,这里逐个介绍一下各个目录和文件的作用:
| .github | git相关目录 |
| build | 构建相关的脚本文件,笔者大概阅读了一下,主要是创建两个Grunt任务,负责构建(bulid)和输出(dist) |
| dist | 输出构建后的文件,主要是jquery.js和jquery.min.js,以及jquery.min.map。这些就是我们最终使用的js文件了 |
| external | 放依赖的第三方代码,jQuery中最重的第三方库sizzle就在这里 |
| node_modules | nodejs的模块文件,构建时候安装的node非全局模块都放在这里,属性nodejs的小伙伴应该很清楚了 |
| src | jQuery自身的源代码的目录,这就是我们主要阅读的部分 |
| test | 单元测试用例 |
| .babelrc | Babel的配置文件 |
| .editorconfig | editorconfig的配置文件,editorconfig是帮助开发者在不同的编辑器和IDE之间定义和维护一致的代码风格的配置,很多ide都支持editorconfig的插件,使用这个就可以使各种ide下都能自动将代码显示成editorconfig约定的格式 |
| .eslintignore | eslint相关文件,配置不用于eslint语法检测的文件目录 |
| .eslintrc.json | eslint的配置文件。eslint和jshint比较像,可以认为是jshint的升级版,都是用来做语法检测的。 |
| .gitattributes | git相关文件,用于设置文件的对比方式 |
| .gitignore | git的配置文件,配置用于配置不需要加入版本管理的文件 |
| .mailmap | 貌似是一个邮件地址列表 |
| .npmignore | npm相关文件,配置哪些文件不需要被发布到npmjs.org |
| .npmrc | npm的配置文件 |
| .travis.yml | Tarvis-CI的配置文件,持续集成用的,github整合了持续集成服务travis,每一次push之后,travis就会定时执行“npm test”来测试项目 |
| AUTHORS.txt | 贡献者名录 |
| CONTRIBUTING.md | 贡献代码指引 |
| Gruntfile.js | Grunt的配置文件 |
| LICENSE.txt | 授权协议 |
| README.md | github项目的说明文档 |
| package.json | npm的包文件 |
几个地方值得注意一下:
1.jQuery是用RequireJs做模块化工具的,所以jQuery的源代码是用AMD规范。AMD这个模块化规范主要活跃于基于浏览器的js模块管理,他有着异步加载、依赖前置等非常好的特性,当然用来做后端的代码模块管理也可以,但是笔者终究认为这里用AMD有点“大材小用”了。jQuery用AMD规范做模块化管理,可能是历史原因的影响,早些年模块化工具不像如今这么成熟。
2.jQuery是用Grunt构建的,jQuery自己做了构建的Grunt任务,具体代码可以参考build目录下的Grunt任务和Grunt的配置文件Gruntfile.js。基于Grunt,jQuery完成测试、构建、合并代码、压缩等工作,最终把构建好的文件拷贝到dist目录里面。
3.jQuery配置了npm包相关的配置,说明jQuery本身也被发布到了npmjs.org上,我们可以直接用npm安装jQuery。
4.jQuery有Babel的配置文件,那源代码是不是用ES6的语法呢?
提问:jQuery有Babel的配置文件,难道jQuery的源代码使用了ES6的语法?
答:答案是没有的,我们先不看Babel在Grunt里面的配置,直接试一下能不能在源代码中使用ES6。
先将源代码里面添加一条ES6的语法,然后执行构建。这时我们会发现构建的时候会报错,而且构建好的jQuery.js文件中ES6的语法也没有被转换为ES5的语法。这说明构建源代码的时候并没有启用Babel。
我们在来看Babel在Grunt里面的配置
babel: {
options: {
sourceMap: "inline",
retainLines: true
},
nodeSmokeTests: {
files: {
"test/node_smoke_tests/lib/ensure_iterability.js":
"test/node_smoke_tests/lib/ensure_iterability_es6.js"
}
}
},
可以看出,Babel仅是将测试用例中的冒烟测试用例做了转换,而源代码则不在被转换列表中。
提问:jQuery的源代码用的是AMD规范做模块化,为什么最终构建好的代码却没有AMD的语句呢?
阅读jQuery的源代码,我们可以很清楚的看到AMD规范的语句。

然后在dist里面的构建好的文件中,我们却找不到AMD规范语句的影子,jQuery是如何去掉了这些AMD语句呢?
答:起初笔者认为是用了一些Grunt上的插件,后来阅读了build里面的代码才发现,是在build里面使用正则将AMD语句去除。jQuery虽然是用的AMD做模块化,但是具体的代码结构还是有自己的一套策略,这个应该就是为了最后构建代码而考虑的。
src的根目录下,共有20多个js文件,很多js文件都有同名的目录与之对应。目录之中最特别的目录就是var目录,因为var目录并不存在与之对应的名为var.js的文件。

var这个名字和js的关键字var相同,这和这个目录这样命名肯定是有关系的。没错,jQuery在去除AMD语句的时候,发现如果是var目录里的文件的话,就会将其转换为“var 文件名 = AMD输出的对象”的形式。如下图:
define( 'var/arr',[],function() {
"use strict";
return [];
} );
define( 'var/document',[],function() {
"use strict";
return window.document;
} );
define( 'var/getProto',[],function() {
"use strict";
return Object.getPrototypeOf;
} );
......
源代码的这几个模块最终会把构建为:
var arr = [];
var document = window.document;
var getProto = Object.getPrototypeOf;
......
而对于非“var”目录下的模块,jQuery会将define关键字等AMD相关的语句直接移除。其中sizzle模块更为特殊,jQuery在构建的时候还做了更多的操作,这里就不再细究了。
分析到这大家也能看出,jQuery这样构建是会破坏AMD各个模块的作用域的。我们之所以需要模块化我们的代码,一点是不希望我们把我们的内部(私有)变量声明到全局作用域中,而JavaScript是一种函数级作用域的语言,jQuery在构建的时候去掉了AMD的函数形式,这样所有模块的代码构建后的都会在同一个作用域里,所以在修改jQuery源代码的时候一定要小心,不要在作用域里面随意创建相同名称的变量,防止造成模块间的冲突。
以上就是jQuery去除AMD的过程。
提问:源码中经常有(#xxxx)这样的注释,他们是什么?
很多地方的注释,都有(#xxxx)的字样,如下:
// Use the original fragment for the last item
// instead of the first because it can end up
// being emptied incorrectly in certain situations (#8070).
答:这些是使用者提出的bug,jQuery的作者们根据bug修复的补丁。jQuery的源码在github上,bug大多都被提到了github上的issues里面,里面的每个bug都有个编号,就是#后面的几个数字,地址“https://github.com/jquery/jquery/issues/”加上这个编号就是bug所在的url了。进入这个url可以查看具体的bug说明和jQuery的作者们对于这个bug的修复情况。除了github的issues,jQuery在其官网也有一个buglist(“https://bugs.jquery.com/ticket/”),不过现在好像访问不了了,这个网站的后面同样有一串数字,#xxxx也有可能指的是这个网址里面bug的id。
了解了jQuery的构建过程后,我们就可以轻松愉快地浏览jQuery的源代码了。事实上如果jQuery构建的时候采用webpack这样的工具就简单多了。jQuery没有采用这样的工具可能也是历史原因,或者是出于进一步优化代码的目的。
jQuery2.x源码解析(构建篇)的更多相关文章
- jQuery2.x源码解析(缓存篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 缓存是jQuery中的又一核心设计,jQuery ...
- jQuery2.x源码解析(设计篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 这一篇笔者主要以设计的角度探索jQuery的源代 ...
- jQuery2.x源码解析(回调篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 通过艾伦的博客,我们能看出,jQuery的pro ...
- jQuery2.x源码解析(DOM操作篇)
jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) jQuery这个类库最为核心重要的功能就是DOM ...
- Shiro源码解析-Session篇
上一篇Shiro源码解析-登录篇中提到了在登录验证成功后有对session的处理,但未详细分析,本文对此部分源码详细分析下. 1. 分析切入点:DefaultSecurityManger的login方 ...
- myBatis源码解析-类型转换篇(5)
前言 开始分析Type包前,说明下使用场景.数据构建语句使用PreparedStatement,需要输入的是jdbc类型,但我们一般写的是java类型.同理,数据库结果集返回的是jdbc类型,而我们需 ...
- myBatis源码解析-反射篇(4)
前沿 前文分析了mybatis的日志包,缓存包,数据源包.源码实在有点难顶,在分析反射包时,花费了较多时间.废话不多说,开始源码之路. 反射包feflection在mybatis路径如下: 源码解析 ...
- Spring源码解析 | 第二篇:Spring IOC容器之XmlBeanFactory启动流程分析和源码解析
一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...
- myBatis源码解析-数据源篇(3)
前言:我们使用mybatis时,关于数据源的配置多使用如c3p0,druid等第三方的数据源.其实mybatis内置了数据源的实现,提供了连接数据库,池的功能.在分析了缓存和日志包的源码后,接下来分析 ...
随机推荐
- Python 爬虫模拟登陆知乎
在之前写过一篇使用python爬虫爬取电影天堂资源的博客,重点是如何解析页面和提高爬虫的效率.由于电影天堂上的资源获取权限是所有人都一样的,所以不需要进行登录验证操作,写完那篇文章后又花了些时间研究了 ...
- 在SQL2008查找某数据库中的列是否存在某个值
在SQL2008查找某数据库中的列是否存在某个值 --SQL2008查找某数据库中的列是否存在某个值 create proc spFind_Column_In_DB ( @type int,--类型: ...
- Spark踩坑记——数据库(Hbase+Mysql)
[TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...
- git克隆项目到本地&&全局安装依赖项目&&安装依赖包&&启动服务
一.安装本地开发环境 1.安装本项目 在需要保存到本地的项目的文件夹,进入到文件夹里点击右键,bash here,出现下图: 2.安装依赖项目 3.安装依赖包(进入到命令行) # 安装依赖包 $ ...
- WebGIS项目中利用mysql控制点库进行千万条数据坐标转换时的分表分区优化方案
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1. 背景 项目中有1000万条历史案卷,为某地方坐标系数据,我们的真实 ...
- CentOS下mysql数据库常用命令总结
mysql数据库使用总结 本文主要记录一些mysql日常使用的命令,供以后查询. 1.更改root密码 mysqladmin -uroot password 'yourpassword' 2.远程登陆 ...
- JavaWeb——ServletContext
一.基本概念 说起ServletContext,一些人会产生误解,以为一个servlet对应一个ServletContext.其实不是这样的,事实是一个web应用对应一个ServletContext, ...
- python 数据类型 -- 元组
元组其实是一种只读列表, 不能增,改, 只可以查询 对于不可变的信息将使用元组:例如数据连接配置 元组的两个方法: index, count >>> r = (1,1,2,3) &g ...
- ubuntu 下安装scrapy
1.把Scrapy签名的GPG密钥添加到APT的钥匙环中: sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 6272 ...
- 海康网络摄像机YV12转换为BGR,由opencv Mat显示 (转)
我使用的是海康DS-2CD852MF-E, 200万,网络摄像机,已经比较老了,不过SDK在海康官网下载的,开发流程都差不多. 海康摄像机回调解码后的视频数据格式为YV12,顺便说一下YV12的数据格 ...