现在,所有主流浏览器都支持JavaScript modules!
本文介绍了如何使用JS modules,如何负责任地部署它们以及Chrome团队如何努力使modules在将来变得更好。
什么是JS模块?
JS模块(也称为“ES模块”或“ECMAScript模块”)是一项主要的新功能,或者是新功能的集合。 您过去可能使用过userland JavaScript模块系统。 也许您在Node.js中使用过CommonJS,或者在AMD中使用过,或者在其他方面使用过。 所有这些模块系统都有一个共同点:它们允许您导入和导出内容。
JavaScript现在已经为此提供了标准化语法。 在模块内,您可以使用export关键字导出几乎所有内容。 您可以export const
,function
或任何其他变量绑定或声明。 只要在变量语句或声明前加上export
前缀,就可以设置好:
// ? lib.mjs export const repeat = (string) => `${string} ${string}`; export function shout(string) { return `${string.toUpperCase()}!`; }
然后,您可以使用import
关键字从另一个module导入module。在这里,我们从lib
module导入repeat
和shout
功能,并在我们的main
module中使用它:
// ? main.mjs import {repeat, shout} from './lib.mjs'; repeat('hello'); // → 'hello hello' shout('Modules in action'); // → 'MODULES IN ACTION!'
您还可以从module导出default
值:
// ? lib.mjs export default function(string) { return `${string.toUpperCase()}!`; }
可以使用任何名称导入此类default
导出:
// ? main.mjs import shout from './lib.mjs'; // ^^^^^
Modules与classic scripts略有不同:
- 默认情况下,模块具有严格模式。
- 模块中不支持HTML样式的注释语法,尽管它可以在classic scripts中使用。
// Don’t use HTML-style comment syntax in JavaScript! const x = 42; <!-- TODO: Rename x to y. // Use a regular single-line comment instead: const x = 42; // TODO: Rename x to y.
- Modules具有词汇top-level范围。 这意味着,例如,运行
var foo = 42;
尽管在classic scripts中就是这种情况,但在modules中创建一个名为foo
的全局变量并不能通过浏览器中的window.foo
进行访问。 - 同样,modules内的
this
不引用全局this
,而是undefined
。(如果需要访问全局this
,请使用globalThis
。) - 新的静态
import
和export
语法仅在modules内可用-在classic scripts中不起作用。 - Top-level
await
在modules中可用,但在classic scripts中不可用。 相关地,尽管classic scripts中的变量可以在异步函数之外命名为await
,但是await
不能在Modules中的任何位置用作变量名。
由于存在这些差异,相同的JavaScript代码在作为module scripts与classic scripts时可能会表现出不同的行为。因此,JavaScript运行时需要知道哪些scripts是modules。
在浏览器中使用JS modules
在网络上,可以通过将type属性设置为module来告诉浏览器将<script>元素视为modules。
<script type="module" src="main.mjs"></script> <script nomodule src="fallback.js"></script>
了解type="module"
的浏览器将忽略具有nomodule
属性的脚本。 这意味着您可以为支持modules的浏览器提供基于modules的有效负载,同时为其他浏览器提供备用。 即使只是为了表现,这种区分的能力也是惊人的! 考虑一下:只有现代的浏览器才支持modules。 如果浏览器了解您的modules代码,则它还支持modules之前的功能,例如箭头函数或async-await
。 您不再需要在modules捆绑包中转换这些功能! 您可以为现代浏览器提供较小的,且未移植的,基于modules的有效负载。 只有旧版浏览器才能获取nomodule
有效负载。
由于默认情况下modules是延迟的,因此您可能还希望以延迟的方式加载nomodule
脚本:
<script type="module" src="main.mjs"></script> <script nomodule defer src="fallback.js"></script>