Skip to content

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。

基于 MIT 许可发布