ES6模块是现代JavaScript工程基础设施,浏览器需type="module"声明,路径须带后缀;export default与named export可混用但导入方式不同;Node.js中CommonJS与ESM不可混用;循环导入返回部分初始化对象。

ES6 模块(import/export)不是“可选增强”,而是现代 JavaScript 工程的基础设施——但直接在浏览器中用 type="module" 加载,或在 Node.js 里开 "type": "module",不处理细节就会报错。
为什么 import 在浏览器里报 “Not a module”?
浏览器只把带 type="module" 的 当作 ES 模块处理,普通 即使写了 import 也会 SyntaxError。
- 必须显式声明:
- 模块脚本默认是
defer行为,且无法访问window上的全局变量(如未用var声明的裸变量) - 路径必须是相对或绝对 URL,
import './utils'不合法,得写成import './utils.js'(Node.js 允许省略后缀,浏览器不行)
export default 和 export 能混用吗?
能,但导入方式完全不同,混用容易搞错引用名。
-
export default function foo() {}→ 导入时名字任意:import anything from './mod.js' -
export const bar = 1; export function baz() {}→ 必须用命名导入:import { bar, baz } from './mod.js' - 不能同时写
export default和export { ... }然后又用import * as ns from想一网打尽——default不会出现在命名空间对象里,得额外解构:import def, * as ns from './mod.js'
Node.js 中 require() 和 import 能共存吗?
不能动态混用:一个文件要么是 CommonJS(require + module.exports),要么是 ESM(import/export),由 "type": "module" 或 .mjs 后缀决定。
立即学习“Java免费学习笔记(深入)”;
- CommonJS 文件里不能写
import,ESM 文件里不能用require()(除非用import('path')动态导入) - 想从 ESM 中加载 CommonJS 包(比如
lodash)?可以:import _ from 'lodash',Node.js 会自动包装,但注意返回的是default导出,没有命名导出 - 反过来,CommonJS 中想加载 ESM?只能用
await import('./mod.js'),且必须在async函数内
循环依赖时 import 返回什么?
ESM 的循环导入不会报错,但返回的是“部分初始化”的模块对象——导出值可能是 undefined,尤其当依赖发生在顶层赋值前。
/* a.js */
import { b } from './b.js';
export let a = 'a';
console.log(b); // undefined
/ b.js /
import { a } from './a.js';
export let b = 'b';
console.log(a); // undefined
关键点:ESM 绑定是“实时绑定”(live binding),不是值拷贝;但初始化顺序导致首次读取时,对方的 export 还没执行完。别依赖循环导入中的顶层变量值,改用函数封装或延迟求值。










