经过阅读源码来提升js知识

经过阅读源码来提升js知识

原文传送门:《Improve Your JavaScript Knowledge By Reading Source Code》javascript

本来做者:Carl Mungazi,是位于伦敦的能源创业公司Limejump的前端开发人员。他花时间深刻挖掘全部JavaScript的深度。html

简介:当你还处于编程生涯的初期阶段时,深刻研究开源库和框架的源代码多是一项艰巨的任务。在这篇文章中,Carl Mungazi分享了他如何克服恐惧并开始使用源代码来提升他的知识和技能。他还使用Redux来演示他如何破坏图书馆。前端

你还记得你第一次深刻挖掘常用的库或框架的源代码吗?对我而言,那一刻是我三年前做为前端开发人员的第一份工做。java

咱们刚刚完成了用于建立电子学习课程的内部遗留框架的重写。在重写开始时,咱们花时间研究了许多不一样的解决方案,包括Mithril,Inferno,Angular,React,Aurelia,Vue和Polymer。由于我是一个很是初学者(我刚重新闻转向网络开发),我记得每一个框架的复杂性让人感到惧怕,而不是理解每一个框架的工做方式。node

当我开始更深刻地研究咱们选择的框架Mithril时,个人理解增加了。从那之后,我对JavaScript的了解 - 以及通常的编程 - 获得了很大的帮助,我花了不少时间深刻研究我天天在工做或我本身的项目中使用的库的内容。在这篇文章中,我将分享一些您能够采用本身喜欢的图书馆或框架并将其用做教育工具的方法。react

如下是我第一次阅读代码的介绍是经过Mithril的hyperscript函数git

我第一次阅读代码的介绍是经过Mithril的hyperscript函数。

阅读源代码的好处

阅读源代码的主要好处之一是增长了你能够学习的知识数量。当我第一次看到Mithril的代码库时,我对虚拟DOM的含义有一个模糊的概念。当我学习完后,我知道虚拟DOM是一种技术,它涉及建立描述用户界面应该是什么样的对象树。而后使用DOM API将该树转换为DOM元素document.createElement。经过建立描述用户界面的将来状态的新树,而后将其与旧树中的对象进行比较来执行更新。github

我在各类文章和教程中也都阅读过这些内容,它对我颇有帮助,而且在咱们发布的应用程序的中可以观察它的运做,对我来讲很是有启发性。它还告诉我在比较不一样的框架时要问哪些问题。例如,我如今会问诸如“每一个框架执行更新的方式如何影响性能和用户体验?”等问题,而不是关注GitHub上的Stars。web

另外一个好处是增长你对优秀应用程序架构的好感和理解。虽然大多数开源项目一般与其存储库遵循相同的结构,但每一个项目都各有差别。Mithril的结构是很是平坦的,若是你熟悉它的API,你能够猜想有关文件夹,如代码renderrouterrequest。另外一方面,React的结构反映了它的新架构。维护者将负责UI更新(react-reconciler)的模块与负责呈现DOM元素(react-dom)的模块分开。chrome

这样作的好处之一是,如今开发人员能够经过挂钩来编写本身的自定义渲染器react-reconciler。我最近研究过的模块捆绑包Parcel也有像React packages这样的文件夹。关键的模块已命名parcel-bundler,它包含负责建立捆绑包,启动热模块服务器和命令行工具的代码。

不久以后,你正在阅读的源代码将引导您进入JavaScript规范。

另外一个好处 —— 令我感到惊讶的是:你能够更轻松地阅读那些定义JavaScript这门语言如何工做的官方规范。我第一次读规范是在我调查的区别throw Errorthrow new Error(扰流警报是none)。我调查了这个由于我注意到Mithril用于throw Error实现它的m功能,我想知道使用它是否比throw new Error更好。从那之后,我还了解到,逻辑运算符&&|| 不必定返回布尔值,发现这个 == 运算是如何强制转换值的规则 ,以及还有Object.prototype.toString.call({}) 返回 '[object Object]'理由 。

阅读源代码的技巧

有不少方法能够处理源代码。我发现最简单的方法是从您选择的库中选择一种方法并记录调用它时会发生什么。不要记录每一步,而要尝试肯定其总体流程和结构。

我最近按这个方式作了ReactDOM.render的记录,也所以学到了不少关于React Fiber及其实现背后的一些缘由。值得庆幸的是,因为React是一个流行的框架,我在同一个问题上遇到了不少其余开发人员撰写的文章,这让我少走不少弯路。

此次深刻探讨还向我介绍了合做调度的概念,window.requestIdleCallback方法和连接列表真实示例(React经过将它们放入队列中来处理更新,队列是优先级更新的连接列表)。执行此操做时,建议使用库建立一个很是基本的应用程序。这使得调试时更容易,由于你没必要处理由其余库引发的堆栈跟踪。

若是我没有进行深刻审查,我将打开/node_modules我正在处理的项目中的文件夹,或者我将转到GitHub存储库。当我遇到错误或有趣的功能时,一般会发生这种状况。在GitHub上阅读代码时,必定要确保你正在阅读的代码是最新的版本。你能够经过单击用于更改分支的按钮并选择“tags”来查看具备最新版本标记的提交中的代码。由于代码库和框架一直都在迭代更新,你固然也不但愿了解一些可能在下一版本中删除的内容,因此及时留意最新的版本。

另外一种复杂点的阅读源代码的方式,我喜欢称之为“粗略一瞥”。在我开始阅读代码的早期,我安装了express.js,打开了它的/node_modules文件夹并安装了它的依赖。若是看了README文件没有给到我很好理解的话,我会直接阅读源码。这样作让我获得了如下这个有趣的发现:

  • Express依赖于两个模块,这两个模块合并对象但以很是不一样的方式这样作。merge-descriptors只添加直接在源对象上直接找到的属性,它还合并不可枚举的属性,同时utils-merge只迭代对象的可枚举属性以及在其原型链中找到的属性。merge-descriptors使用Object.getOwnPropertyNames()Object.getOwnPropertyDescriptor()同时utils-merge使用for..in;
  • setprototypeof模块提供了一种设置实例化对象原型的跨平台方式;
  • escape-html 是一个78行模块,用于转义一串内容,以即可以在HTML内容中进行插值。

虽然这些发现并不能立刻运用,可是让你对代码库或框架使用的依赖关系有一个大体的了解。

在调试前端代码时,浏览器的调试工具是你最好的朋友。除此以外,它们可让你随时中断程序运行并检查当前的状态,再决定跳过函数的执行或进入或退出程序。若是代码已经压缩过,可能没法很好地进行调试。我我的就喜欢把没有压缩的代码复制到/node_modules文件夹中的相关文件中,再将其进行解析。

案例研究:Redux的Connect链接功能

React-Redux是一个用于管理React应用程序状态的库。在处理诸如此类的流行库时,我首先会搜索一些写过有关其实现的文章。在本案例研究中,我遇到了这篇文章。这是阅读源代码的另外一个好处。研究阶段一般会引导你阅读这样的文章,这些文章会改善你本身的思考和理解。

connect是一个React-Redux函数,它将React组件链接到应用程序的Redux存储。他是怎么作的呢?根据文档,它作了如下事情:

“...返回一个新的,链接的组件类,它包装你传入的组件。”

看完以后,我会问下列问题:

  • 我是否知道函数接受输入的任何模式或概念,而后返回包含其余功能的相同输入?
  • 若是我知道任何这样的模式,我将如何根据文档中给出的解释实现这一点?

一般,下一步是建立一个使用的很是基本的示例应用程序connect。可是,在这种状况下,我选择使用咱们在Limejump上构建的新React应用程序,由于我想connect在最终将进入生产环境的应用程序的上下文中理解。

我关注的组件看起来像这样:

class MarketContainer extends Component { // code omitted for brevity } const mapDispatchToProps = dispatch => { return { updateSummary: (summary, start, today) => dispatch(updateSummary(summary, start, today)) } } export default connect(null, mapDispatchToProps)(MarketContainer); 

它是一个容器组件,包裹着四个较小的链接组件。你在文件中遇到的第一个导出connect方法是注释:connect是connectAdvanced上的外观。没有走得太远,咱们就有了第一个学习时刻:一个观察立面设计模式的机会。在文件的末尾,咱们看到connect导出一个名为的函数的调用createConnect。它的参数是一堆已被解构的默认值,以下所示:

export function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories = defaultMapStateToPropsFactories, mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, mergePropsFactories = defaultMergePropsFactories, selectorFactory = defaultSelectorFactory } = {}) 

一样,咱们遇到了另外一个学习时刻:导出调用函数解构默认函数参数。解构部分是一个学习时刻,由于代码编写以下:

export function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories = defaultMapStateToPropsFactories, mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, mergePropsFactories = defaultMergePropsFactories, selectorFactory = defaultSelectorFactory }) 

它会致使发生这个错误。Uncaught TypeError: Cannot destructure property 'connectHOC' of 'undefined' or 'null'. 这是由于这个函数没有默认参数可供使用。

注意有关此内容的更多信息,请阅读David Walsh的文章。根据你对语言的了解,一些学习时刻可能看起来微不足道,所以最好将注意力放在您之前从未见过或须要了解更多信息的事情上。

createConnect它自己在函数体中没有任何做用。它返回一个名为的函数connect,我在这里使用的函数:

export default connect(null, mapDispatchToProps)(MarketContainer) 

它须要四个参数,都是可选的,前三个参数都经过一个match函数来帮助根据参数是否存在以及它们的值类型来定义它们的行为。如今,由于提供的第二个参数match是导入的三个函数之一connect,我必须决定要遵循哪一个线程。

若是这些参数是函数,用于包装第一个参数的代理函数connectisPlainObject用于检查普通对象的实用程序或warning揭示如何设置调试器以中断全部异常的模块,有学习时刻。在匹配函数以后,咱们来了connectHOC一个函数,它接受咱们的React组件并将它链接到Redux。它是另外一个返回的函数调用,wrapWithConnect它实际上处理将组件链接到存储的函数。

看看connectHOC它的实现,我能够理解为何它须要connect隐藏它的实现细节。它是React-Redux的核心,包含不须要经过暴露的逻辑connect。尽管我本来打算在这个地方结束对它的深度探讨,我也会继续,这也将是我翻查以前发现的参考资料的最佳时机,由于有些资料对对代码库的解释很是详细。

摘要

阅读源代码一开始是很困难的,但跟任何事情同样,随着时间的推移它会慢慢变得更容易。咱们的目标不是说要理解每一行代码,而是要经过阅读进而获得不一样的视角和新的知识。关键是既对整个过程进行深思熟虑,也要对全部事情充满好奇。

例如,我发现isPlainObject函数颇有趣,由于它使用它if (typeof obj !== 'object' || obj === null) return false来确保给定的参数是一个普通的对象。当我第一次阅读它的实现过程,我想知道为何它没有使用Object.prototype.toString.call(opts) !== '[object Object]',这样会产生更少的代码并能区分对象和对象子类型,好比Date对象。可是,阅读下一行意识到,在开发人员几乎没法用connect去返回一个Date对象,好比,这个是由Object.getPrototypeOf(obj) === null 进行检查校验的。

另外一个很吸引人的是在isPlainObject中的这段代码:

while (Object.getPrototypeOf(baseProto) !== null) { baseProto = Object.getPrototypeOf(baseProto) } 

在谷歌搜索的时候,有些会引导我进入这个 StackOverflow社区 或 Redux issue 查看关于该代码如何处理的案例,例如检查iFrame的对象来源。

另外,还有一些有利于阅读源码的文章

Finish

【做者简介】:土拨鼠,芦苇科技web前端开发工程师,表明做品:飞花亭小程序、续航基因、YY表情红包、YY叠方块直播竞赛小游戏。擅长网站建设、公众号开发、微信小程序开发、小游戏、公众号开发,专一于前端框架、服务端渲染、SEO技术、交互设计、图像绘制、数据分析等研究。

欢迎和咱们一块儿并肩做战: web@talkmoney.cn

访问 www.talkmoney.cn 了解更多

相关文章
相关标签/搜索