这篇文章提供了关于如何更好地组织JavaScript模块的4个最佳实践。尽可能使用命名导出当开始使用JavaScript模块时,使用exportdefault导出模块定义的单个块,无论它是类还是函数。例如://greeter.jsexportdefaultclassGreeter{constructor(name){this.name=name;}greet(){return`Hello,${this.name}!`;}}从'./greeter.js'随着时间的推移,尤其是在做大规模重构的时候,很难根据Greeter找到相关的参考资料。可维护性大大降低。更糟糕的是,小编不提供建议,需要我们自己写Importedclassnames。因此,我们转向命名导出。让我们看看它有什么用://greeter.jsexportclassGreeter{constructor(name){this.name=name;}greet(){return`Hello,${this.name}!`;}}import{Greeter}from'./greeter.js'通过使用命名导出,编辑器可以更好地重命名:每次更改原始类名时,所有消费者模块都会自动更改类名。并且小编也会给出建议,不再盲目敲代码,如下:因此,建议使用namedexports,以便受益于重命名重构和代码自动补全。注意:使用React、Lodash等第三方模块时,通常默认import即可。因为他们导入的名字是一个不可变的常量:React,_。惰性导入对象模块级作用域不应进行繁重的计算,如解析JSON、发出HTTP请求、读取本地存储等。例如,下面的模块配置从全局变量bigJsonString解析配置//configuration.jsexportconstconfiguration={//Baddata:JSON.parse(bigJsonString)};这是一个问题,因为bigJsonString的解析是在模块级范围内完成的。当导入配置模块时,bigJsonString实际上会被解析://Bad:parsinghappenswhenthemoduleisimportedimport{configuration}from'configuration';exportfunctionAboutUs(){return
{configuration.data.siteName}
;}在更高层次上,模块级范围的作用是定义模块组件、导入依赖项和导出公共组件:这就是依赖解析过程。它应该与运行时分离:解析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}
;}消费者更清楚何时进行大型操作。用户可以决定在浏览器空闲时执行此操作。或者,消费者可以导入一个模块,但出于某种原因,不使用它。这为更深入的性能优化开辟了机会:减少交互时间并最大限度地减少主线程工作。模块在导入时不应执行任何繁重的工作。相反,消费者应该决定何时执行运行时操作。编写高内聚的模块内聚描述了模块中的组件如何属于整体。高内聚模块的函数、类或变量密切相关。他们专注于一项任务。formatDate模块是高度内聚的,因为它的功能密切相关。//formatDate.jsconstMONTHS=['一月','二月','三月','四月','五月','六月','七月','八月','九月','十月','十一月','十二月'];函数ensureDateInstance(date){if(typeofdate==='string'){returnnewDate(date);}返回日期;}导出函数formatDate(date){date=ensureDateInstance(date);constmonthName=MONTHS[date.getMonth())];返回`${monthName}${date.getDate()},${date.getFullYear()}`;}formatDate()、ensureDateInstance()和MONTHS彼此密切相关。删除MONTHS或ensureDateInstance()会破坏formatDate():这是高内聚的标志。低内聚模块的问题另一方面,低内聚模块。指那些包含彼此不相关的组件。下面的utils模块有3个函数来执行不同的任务。//utils.js从'cookies'导入cookies;exportfunctiongetRandomInRange(start,end){returnstart+Math.floor((end-start)*Math.random());}exportfunctionpluralize(itemName,count){returncount>1?`${itemName}s`:itemName;}exportfunctioncookieExists(cookieName){constcookiesObject=cookie.parse(document.cookie);returncookieNameincookiesObject;}getRandomInRange(),pluralize()和cookieExists()去除任何功能,不会影响整个模块的功能。低内聚模块迫使用户依赖他们不需要的模块,这会产生不必要的Required传递依赖。例如,组件ShoppingCartCount从utils模块导入pluralize()函数//ShoppingCartCount.jsximport{pluralize}from'utils';exportfunctionShoppingCartCount({count}){return(