5.3 Lodash.js的源码结构

本章的最后一节将详细介绍Lodash.js的基本框架结构。官方代码仓库中的Lodash.js文件是完整的代码,其中包含的大量注释可以帮助开发者理解代码的意图。

5.3.1 基本结构

1. 模块化结构

如果在编辑器中将代码折叠起来,就能看到Lodash.js的最外层代码框架如下所示:

;(function(){}.call(this));

第4章中介绍过这种代码结构,从模块外部传入参数“this”,就可以让Lodash.js脱离对环境的依赖,因为浏览器环境与Node.js环境中全局“this”的指向是不同的。Lodash.js会先将方法聚合在一起,然后在整个代码的最后部分根据运行环境支持的模块化标准选择导出方式,尽管其没有使用通用的模块定义(UMD)规范的代码范式,但基本思想是完全一致的。

2. 面向对象思想

Lodash.js中导出的“_”标识符并不仅仅是一个聚合了各种方法的命名空间,同时也是一个用于生成Lodash包装对象的工厂函数。事实上,这种结构与jQuery是一致的,jQuery中的“$”既可以作为静态方法的命名空间(例如直接使用“$.each”“$.ajax”等方法),也可以作为jQuery包装对象的构造方法(传入查询字符串后返回jQuery包装对象,而不是原生的DOM节点),jQuery包装对象可以直接使用更丰富的方法来操作文档对象模型(DOM),并通过在方法体中返回“this”来实现链式调用,因为原型对象方法中的“this”是指向实例的。Lodash.js的做法与jQuery如出一辙,只不过它针对的不是文档对象模型元素,而是JavaScript中的引用类型。如果你喜欢链式调用风格的代码,则可以使用“_”将原生类型转换成一个Lodash包装对象。从源代码中我们可以发现,前面启用链式调用时使用的“_.chain()”方法实际上是将数据集作为参数传入构造函数,然后返回一个新的Lodash包装对象,使得它可以访问定义在Lodash原型对象上的那些支持链式调用的方法,这个看起来非常神奇的操作只有3行代码。这里需要注意的是,Lodash.js对外暴露的构造函数是一个工厂方法,根据传入参数的不同,该方法会以不同的方式返回包装对象,只有在传入了未被包装的数组或对象类型的值时才会生成新的包装对象。

了解了Lodash.js的基本结构之后,剩下的工作就是编写内部函数和对外暴露的工具函数了,其中会涉及大量的JavaScript基础知识和编程技巧,但它们并不会对整体架构造成影响,感兴趣的读者完全可以自学,限于篇幅本书不再赘述。

5.3.2 Lodash.js源码的学习方法

笔者曾经阅读过很多分析Lodash.js源码的文章,它们能帮助笔者更好地理解这些代码,但直到自己动手实践之后,笔者才能逐渐运用那些经典原则和抽象编程知识来改善自己的代码。如果你只想要高效且省力的工作,那么熟练使用API就可以了;如果你想要成为高手,就需要搞清楚API背后的逻辑和原理;如果你想要成为大师,就需要将经典代码中包含的思想和技巧内化为自己的能力。现代前端开发通常是基于框架来进行的,除了声明式的组件代码之外,使用Lodash.js改善代码的细节几乎是初级工程师唯一可以自由发挥的部分。

如果决定开始学习Lodash.js的源码(默认你已经了解了Lodash.js中大部分常用的API),可以从官方代码仓库复制一份完整版的Lodash.js源代码,大约有17 000行,不要担心,其中多半都是注释,你的目标很简单,就是从这份完整的Lodash.js源码中逐步删除自己已经掌握的代码,直到它成为一个空文件为止。建议从自己最常用的那些方法开始,先试着自己去编写它,然后到官方代码仓库中找到对应方法的独立模块文件,看看Lodash.js是如何实现该方法的,确认自己已经搞清楚相关的知识之后,将它从你复制的Lodash.js中删除,或者将自己的收获写成博文分享给其他人,随着那份源代码的行数不断减少,你就能感知到自己的进步了。不用赶进度,一定要做得足够细。秘籍就在这里,能否成为高手,就看自己愿意付出多少了。