与传统的命名空间相比,ES6导出/导入用例

vsy*_*ync 4 javascript ecmascript-6

我不明白为什么以及在什么情况下这将被使用..

我当前的Web设置包含许多组件,这些组件只是函数或工厂函数,每个组件都在自己的文件中,每个函数都"骑"到app命名空间,如:app.component.breadcrumbs = function(){...等等.

然后GULP只是组合了所有文件,最后我得到了一个文件,所以页面控制器(每个"页面"都有一个加载页面所需组件的控制器)可以加载它的组件,如:app.component.breadcrumbs(data).

所有组件都可以按需轻松访问,单个javascript文件可以很好地缓存所有内容.这种工作方式似乎非常好,从未发现这种工作方式存在任何问题.当然,这可以(并且是)很好地缩放.

那么ES6如何为功能输入比我描述的更好?

导入函数的处理是什么,而不是仅将它们附加到App的命名空间?让他们"依恋"更有意义.

文件结构

/dist/app.js                     // web app namespace and so on
/dist/components/breadcrumbs.js  // some component
/dist/components/header.js       // some component
/dist/components/sidemenu.js     // some component
/dist/pages/homepage.js          // home page controller

// GULP concat all above to
/js/app.js // this file is what is downloaded
Run Code Online (Sandbox Code Playgroud)

然后里面homepage.js看起来像这样:

app.routes.homepage = function(){
    "use strict";
    var DOM = { page : $('#page') };

    // append whatever components I want to this page
    DOM.page.append(
        app.component.header(),
        app.component.sidemenu(),
        app.component.breadcrumbs({a:1, b:2, c:3})
    )
};
Run Code Online (Sandbox Code Playgroud)

这是一个极其简化的代码示例,但您明白了

log*_*yth 6

对此的回答可能有点主观,但我会尽我所能.

在一天结束时,这两种方法都允许支持为一段功能创建命名空间,以便它不会与其他事物冲突.两者都有效,但在我看来,模块,ES6或任何其他模块都提供了一些额外的好处.

显式依赖

你的例子似乎非常倾向于"加载一切"的方法,但你通常会发现这种情况并不常见.如果您components/header.js需要使用components/breadcrumbs.js,必须做出假设.该文件是否已捆绑到整个JS文件中?你无从知晓.你有两个选择

  1. 加载一切
  2. 在某处明确列出需要加载的文件.

第一种选择很简单,在短期内可能很好.第二个是可维护性很复杂,因为它将作为外部列表维护,很容易停止需要你的一个组件文件但忘记删除它.

这也意味着您实际上已经为依赖关系定义了自己的语法,现在已经在语言/社区中定义了一个.

当您想要将应用程序拆分成碎片时会发生什么?假设您的应用程序是一个大型文件,可以在您的网站上运行5个页面,因为它们起初很简单并且不够重要.现在应用程序已经增长,应该每页提供一个单独的JS文件.你现在已经失去了使用选项#1的能力,而一些可怜的灵魂需要为每个结束文件构建这个新的依赖列表.

如果您开始在新地方使用文件怎么办?你怎么知道哪些JS目标文件实际需要它?如果您有20个目标文件怎么办?

如果您拥有整个公司使用的组件库,并且其中一个组件开始依赖新的东西,该怎么办?如何将这些信息传播给使用这些信息的任何数量的开发人员?

通过模块,您可以100%确定地了解使用自动化工具的地方.您只需要打包实际使用的文件.

订购

与依赖性列表相关的是依赖性排序.如果您的图书馆需要创建一个特殊的子header.js组件,你不再是唯一的访问app.component.header()从app.routes.homepage(),这将在推测被DOMContentLoaded运行.相反,您需要在初始应用程序执行期间访问它.简单连接不能保证它将运行.如果你按字母顺序连接,那么你的新东西app.component.blueHeader()就会失败.

这适用于您可能希望在执行时立即执行的任何操作.如果你有一个模块在运行时立即查看页面,或发送一个AJAX请求或任何东西,如果它依赖于某些库来做什么呢?

这是#1(加载所有内容)的另一个参数,因此您必须再次维护列表.该列表将再次成为您将提出的自定义内容,而不是标准化系统.

您如何培训新员工使用您构建的所有自定义内容?

模块根据它们的依赖关系按顺序执行文件,因此您可以确定您所依赖的内容已经执行并且可用.

作用域

您的解决方案将所有内容视为标准脚本文件.这很好,但这意味着您需要非常小心,不要通过将全局变量放在文件的顶级范围内而意外地创建全局变量.这可以通过手动添加(function(){ ... })();文件内容来解决,但同样,这是您需要知道的一件事,而不是通过语言为您提供.

冲突

app.component.*是你选择的东西,但没有什么特别之处,它是全球性的.如果你想从Github引入一个新的库,并且它也使用相同的名称怎么办?您是否重构整个应用程序以避免冲突?

如果您需要加载两个版本的库,该怎么办?如果它很大,那么它有明显的缺点,但是在很多情况下你仍然希望通过非功能性进行大交易.如果你依赖于一个全局对象,现在由该库来确保它还公开了一个类似jQuery的API noConflict.如果没有怎么办?你必须自己添加吗?

鼓励更小的模块

这个可能更有争议,但我肯定在我自己的代码库中观察到它.使用模块,并且缺乏用它们编写模块化代码所需的样板文件,鼓励开发人员密切关注事物如何分组.最终制作"utils"文件非常容易,这些文件是成千上万行的巨大功能包,因为它更容易添加到现有文件中以制作新文件.

依赖网络

具有明确的导入和导出使得很清楚什么取决于什么,这很好,但副作用是,更容易批判性地思考依赖关系.如果你有一个包含100个辅助函数的巨型文件,这意味着如果这些帮助程序中的任何一个需要依赖于来自另一个文件的东西,则需要加载它,即使此刻没有任何东西使用该辅助函数.这很容易导致大量不明确的依赖关系,并且意识到依赖关系是阻止这种情况的重要一步.

标准化

标准化还有很多要说的.JavaScript社区已经朝着可重用模块的方向发展.这意味着如果您希望进入新的代码库,则无需首先弄清楚事物与彼此之间的关系.你的第一步,至少从长远来看,不会想知道是AMD,CommonJS,System.register还是什么.通过在语言中使用语法,可以做出更少的决定.

它的长短之处在于,模块为代码提供了标准的互操作方式,无论是您自己的代码还是第三方代码.

您当前的过程是将所有内容连接到一个大型文件中,只在整个文件加载后执行,并且您可以100%控制正在执行的所有代码,然后您基本上定义了自己的模块规范.您自己对特定代码库的假设.这完全没问题,没有人强迫你改变它.

但是,对于JavaScript代码的一般情况,不能做出这样的假设.模块的目标恰恰是以不破坏现有代码的方式提供标准,而且还为社区提供前进的方法.模块提供的另一种方法是标准化的方法,并为您自己的代码和第三方代码之间的互操作性提供更清晰的路径.