主题
import
import 用于从其他模块读取导出的绑定。它描述的是“当前模块依赖什么”。
import 的基本特点
可以先记住三点:
- 只能导入别的模块已经导出的内容
- 导入语句默认是静态的
- 导入的绑定不能在当前模块里重新赋值
js
import { count } from './counter.js'
// count = 2 // SyntaxError 或 TypeError这里不能重新给 count 赋值,但如果导出的是对象,修改对象内部属性仍然可能影响共享结果。
具名导入
最常见的是按名称导入:
js
import { add, multiply } from './math.js'如果导出名太长或想避免冲突,可以重命名:
js
import { add as sum } from './math.js'默认导入
如果模块使用了默认导出,可以直接导入一个值:
js
import formatDate from './format.js'默认导入拿到的是模块的 default 导出,变量名由当前文件自己决定。
同时导入默认导出和具名导出
js
import formatDate, { parseDate } from './date.js'这种写法适合模块既暴露一个主能力,又暴露少量辅助能力的情况。
命名空间导入
如果想把整个模块作为一个对象来使用,可以写成:
js
import * as math from './math.js'
console.log(math.add(1, 2))这会把模块的所有具名导出挂到 math 上。
仅执行模块,不接收导出值
有时导入模块只是为了执行它的副作用:
js
import './setup.js'常见场景包括:
- 注册全局配置
- 安装 polyfill
- 初始化运行环境
动态导入
如果依赖不是一开始就确定,或者希望按需加载,可以使用 import():
js
const module = await import('./math.js')
console.log(module.add(1, 2))import() 是一个返回 Promise 的表达式,不是静态导入语句。
动态导入适合什么场景
更适合:
- 按条件加载模块
- 延迟加载大体积代码
- 路由级代码拆分
- 运行时再决定依赖路径
如果依赖关系是固定的,通常优先使用静态 import。
import 为什么必须写在顶层
静态 import 之所以不能放进 if、函数、循环里,是因为运行环境需要在执行前先完成依赖分析。
js
// if (flag) {
// import { add } from './math.js'
// }这种写法对静态导入无效;需要条件加载时应该改用 import()。
导入的是 live binding
导入拿到的不是值快照,而是对导出绑定的读取。
js
// counter.js
export let count = 0
export function increment() {
count += 1
}js
// main.js
import { count, increment } from './counter.js'
console.log(count) // 0
increment()
console.log(count) // 1这也是为什么导入项本身不能在当前模块里重新赋值。
使用建议
- 依赖关系固定时,优先用静态
import。 - 只在确实需要按需加载时再用
import()。 - 默认导入和具名导入混用前,先确认模块对外接口是否清晰。
- 看到导入报错时,先检查路径、导出方式,以及当前环境是否支持 ESM。
