当前位置: 首页 > 后端技术 > Node.js

编写高质量JavaScript模块的4个最佳实践

时间:2023-04-03 17:04:25 Node.js

使用ES2015模块,您可以将应用程序代码分成可重用的、封装的模块,专注于单个任务。那很好,但是你如何构建你的模块?一个模块应该有多少个函数和类?这篇文章涵盖了关于如何更好地组织JavaScript模块的4个最佳实践。1.更喜欢命名导出当我开始使用JavaScript模块时,我使用默认语法导出单个模块定义块,无论它是类还是函数。例如,这是一个模块程序,它默认导出模块Greeter://greeter.jsexportdefaultclassGreeter{constructor(name){this.name=name;}greet(){return`Hello,${this.name}!`;}}随着时间的推移,我注意到重构默认导出的类(或函数)的难度。重命名原始类时,消费者模块中的类名没有改变。更糟糕的是,编辑器没有为要导入的类名提供自动完成建议。我的结论是默认导出不会提供显着的好处。然后我继续进行命名导出。让我们将Greeter命名为导出并查看好处://greeter.jsexportclassGreeter{constructor(name){this.name=name;}greet(){return`Hello,${this.name}!`;}}使用命名导出,编辑器可以更好地重命名:每次更改原始类名时,所有消费者模块也会更改类名。自动完成还建议导入类:因此,这是我的建议:“支持命名模块导出以从重命名重构和代码完成中获益。”注意:当使用React、Lodash等3rd方模块时,默认导入通常没问题。默认导入名称是一个不可变常量:React,_.2.导入时没有繁重的计算工作模块级作用域定义了函数、类、对象和变量。该模块可以导出其中的一些组件。就这样。//Module-levelscopeexportfunctionmyFunction(){//myFunctionScope}一个模块级作用域不应该做像解析JSON,发出HTTP请求,读取本地存储等繁重的计算。例如,下面的模块配置解析配置来自全局变量bigJsonString://configuration.jsexportconstconfiguration={//错误数据:JSON.parse(bigJsonString)};这是一个问题,因为bigJsonString的解析是在模块级别范围内完成的。bigJsonString的解析实际上发生在导入配置模块时://Bad:Parsingwhenimportingthemoduleimport{configuration}from'configuration';exportfunctionAboutUs(){return

{configuration.data.siteName}

;}在更高层次上,模块级作用域的作用是定义模块组件,导入依赖,导出公共组件:this是依赖解析过程。它应该与运行时分离:解析JSON、发出请求、处理事件。让我们重构配置模块来进行惰性解析://configuration.jsletparsedData=null;exportconstconfiguration={//Goodgetdata(){if(parsedData===null){parsedData=JSON.parse(bigJsonString);}返回解析数据;}};因为data属性被定义为getter,bigJsonString只有在用户访问configuration.data时才会被解析。//好:导入模块时不执行JSON解析import{configuration}from'configuration';exportfunctionAboutUs(){//JSON解析只在调用时执行return

{configuration.data.companyDescription}

;}消费者更清楚什么时候执行大操作,用户可能决定在浏览器空闲时执行操作。或者,消费者可能会导入一个模块,但由于某种原因不使用它。这为更深入的性能优化开辟了机会:减少交互时间并最大限度地减少主线程工作。模块在导入时不应执行任何繁重的工作。相反,消费者应该决定何时执行运行时操作。3、尽量使用高内聚。模块内聚性描述了模块内各个组件在一起的程度。高内聚模块的函数、类或变量密切相关。他们专注于一项任务。formatDate模块具有高度内聚性,因为它的功能密切相关并专注于日期格式化://formatDate.jsconstMONTHS=['January','February','March','April','May','June','七月','八月','九月','十月','十一月','十二月'];函数ensureDateInstance(date){if(typeofdate==='string'){returnnewDate(date);}返回日期;}导出函数formatDate(date){date=ensureDateInstance(date);constmonthName=MONTHS[date.getMonth())];return`${monthName}${date.getDate()},${date.getFullYear()}`;}formatDate(),ensureDateInstance()和MONTHS彼此密切相关。删除MONTHS或ensureDateInstance()会破坏formatDate():这是高内聚的标志。4.避免过长的相对路径我发现很难理解一个模块的路径包含一个,甚至更多的父文件夹:import{compareDates}from'../../date/compare';import{formatDate}from'../../date/format';//在只有一个父选择器的情况下使用compareDates和formatDate../通常不是问题,有2个或更多通常很难掌握。这就是为什么我建议避免使用父文件夹并改用绝对路径:import{compareDates}from'utils/date/compare';从'utils/date/format'导入{formatDate};//使用compareDates和formatDate虽然有时写绝对路径的时间比较长,但是使用绝对路径使得导入模块的位置没有歧义。为了减少冗长的绝对路径,可以引入一个新的根目录。例如,这可以使用babel-plugin-module-resolver来实现。使用绝对路径而不是长的相对路径。5.结论JavaScript模块非常适合将应用程序逻辑分解成多个独立的小块。通过使用命名导出而不是默认导出来导入命名组件时,更容易重命名重构和编辑器自动完成帮助。使用import{myFunc}from'myModule'的唯一目的是导入myFunc组件,仅此而已。myModule的模块级作用域应该只定义包含少量内容的类、函数或变量。一个组件应该有多少个函数或类,这些函数或类应该如何与每个组件相关联?支持高内聚的模块:它的组件应该密切相关并执行共同的任务。具有许多父文件夹的长相对路径../很难理解。将它们重构为绝对路径。您使用哪些JavaScript模块最佳实践?原文:https://dmitripavlutin.com/ja...作者:DmitriPavlutin译者:做工程师,不是coder,关注公众号,第一时间收到最新文章。如果对你有一点帮助,可以点赞、点赞、收藏,也可以小额打赏作者,鼓励作者写出更多更好的文章。

猜你喜欢