ES6 中的模块化规范是一个重要的进步。它将前端开发推向了更加规范化和优秀的方向。在 ES6 之前,我们通常采用 CommonJS 或者 AMD 规范来实现模块化编程。然而,由于过度的商业化和非标准化的问题,这些规范并不能在跨浏览器和跨平台的开发环境中完全运用。因此,ES6 提供了一个新的外部模块规范会呈现更为优秀的表现。
解析 ES6 模块
ES6 模块系统的基础是引用的静态解析。如果一个模块定义了一个导入,则使用的模块可通过其编号进行寻址。当模块被解析且其依赖项被加载时,则其定义被运行且产生一个值。从概念上讲,JavaScript 代码具有完整的模块注册中心,所有模块代码都必须通过该中心导出才能被其他模块加载。
导出和导入
在 ES6 模块中,通过 export
关键字来导出一个模块, export
关键字可以是一个变量,函数 或者类等等。例如,我们可以定义一个叫做 moduleName.js
的模块,并导出两个函数,一个叫 foo
,另一个叫 bar
。
export function foo() { return 'foo'; } export function bar() { return 'bar'; }
然后,在另一个文件中使用 import
关键字引用该模块:
import { foo } from './moduleName.js'; console.log(foo()); // => 输出 "foo"
在上述示例中,我们从 moduleName.js
模块中仅仅导入了函数 foo()
。这意味着我们不能在当前文件中使用函数 bar()
。
导出默认值
ES6 支持将某个模块中的某一项作为默认值导出。这样,它就能够在其他地方通过一个更加简短的名称导入。例如,在上述示例中,我们可以将 moduleName.js
中定义的 bar()
函数作为默认值导出:
export default function bar() { return 'bar'; }
然后,可以通过不同的语法将其导入:
import foo, { bar } from './moduleName.js'; console.log(foo()); // => 输出 "foobar" console.log(bar()); // => 输出 "bar"
动态导入
ES6 在模块加载方面引入了许多的便利之处,其中一种方式就是通过动态加载模块来引入:
const myModule = await import(`${path}/moduleName.js`); console.log(myModule.foo());
模块之间的循环引用
我们知道,在传统的 CommonJS 或者 AMD 规范下,循环依赖是会发生问题的。但在 ES6 的模块规范中,会自动处理循环依赖的问题:
-- -------------------- ---- ------- -- -------- ------ - ----- - ---- ------------- ------ -------- ------- - ------ ---- - -------- -- -------- ------ - ----- - ---- ------------- ------ -------- ------- - ------ ---- - --------
在上述示例中,我们定义了两个模块并互相引用。在 ES6 规范下,这样的循环依赖是不会产生问题的。
模块加载
在 ES6 模块系统下,加载外部模块的方式是异步的,使用了 Promise 机制。JavaScript 引擎自动将代码分离成不同的块,在代码需要的时候才加载。
例如,在下面的例子中,我们使用 import()
动态加载依赖的模块。因为它返回一个 Promise,所以我们需要使用 .then()
来获取导出的内容:
import('/moduleName.js') .then(module => { console.log(module.foo()); }) .catch(err => { console.error(err); });
总结
在 ES6 中,模块应该是编写 JavaScript 代码的主要方式之一。它提供了许多功能和工具,可以让我们将代码分解为可读的小段,并使其易于维护。不论是在前端还是后端,模块都是一种向着更为优秀的编码方式的发展。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/646870e7968c7c53b08a6f1d