浏览器原生支持ES模块需显式启用:通过<script type="module">或.mjs后缀;import/export必须在模块上下文中运行,路径须带扩展名和相对前缀,导出方式决定导入语法,模块脚本默认严格模式、顶层this为undefined、自动defer且支持顶层await。

浏览器原生支持 ES 模块(ESM),但 import 和 export 不是“写了就能用”的语法糖——它们必须运行在明确启用模块系统的上下文中,否则直接报错(如 Unexpected token 'export')。关键不在语法本身,而在环境声明与路径规则。
必须显式启用模块模式
浏览器默认把 <script src="xxx.js"> 当作传统脚本(classic script),不识别 import/export。启用原生模块只有两种等效方式:
- 在
<script>标签中添加type="module"属性,例如:<script type="module" src="main.js"></script> - 将文件后缀改为
.mjs,并在 HTML 中仍用type="module"引入(注意:仅本地file://协议下可靠;生产环境必须通过 HTTP 服务提供)
没加 type="module" 的 .js 文件,哪怕写满 export 也会语法报错,不是“无效”,而是根本未被解析为模块。
导出写法决定导入方式
导出不是“随便扔出去”,每种写法对应唯一的合法导入形式,混用必出 undefined 或 ReferenceError:
-
export const foo = 1;→ 必须用import { foo } from './mod.js';(具名导入,名字不可改) -
export default function bar() {}→ 可用import bar from './mod.js';(默认导入,名字任意) -
export { foo as baz };→ 导入时只能写import { baz } from './mod.js';,foo不可见 - 禁止
export default const x = 1;—— 默认导出只接受表达式,如export default 1;、export default class {};、export default () => {};
路径必须带扩展名且含相对前缀
浏览器 ESM 不支持 Node.js 那套自动补 .js 或查找 index.js 的逻辑:
- 路径必须包含扩展名:
import { x } from './utils.js';✅,import { x } from './utils';❌ - 必须显式写出相对路径前缀:
import { x } from 'utils.js';(无./)会报错,属于“裸说明符”(bare specifier),浏览器不支持 - 支持
./(同级)、../(上级)、/(根路径)等标准 URL 形式,但不能省略协议或前缀
模块脚本自带行为特性
一旦启用 type="module",脚本自动获得以下特性,无需额外配置:
- 默认启用严格模式(
"use strict") - 顶层
this为undefined(非window) - 执行时机类似
defer:DOM 解析完成后再执行,无需手动监听DOMContentLoaded - 脚本只执行一次,即使多个
<script type="module">引入同一模块,也只初始化一次 - 支持顶层
await,可直接在模块顶层等待 Promise


















