前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库ESM 副作用导入 import 模块
JSJavaScript模块与语言机制

纯副作用导入 import './module' 有什么用途,它会执行模块代码吗?

会执行模块的顶层代码,但不会向当前作用域引入任何绑定;它专用于那些只需模块执行副作用的场景,比如注册或补丁。

前端进阶之旅 · 一题精讲更新于 2026.09.05
JavaScript#模块与语言机制
先看核心答案
理解线索

纯副作用导入

  1. 无绑定不把导出引入当前作用域。
  2. 执行代码模块顶层全部运行一次。
  3. 用于副作用如 polyfill、注册操作。

它区别于命名导入、默认导入和命名空间导入,只关心模块求值效果。

核心回答

先记住这个答案

会。import './module' 会加载并执行该模块的顶层代码,包括所有可执行的副作用语句,但不会把任何导出绑定到当前模块作用域。它用于只需模块运行效果(如全局注册、环境初始化)而无需引用其导出的情形,且模块只执行一次。

  • 纯副作用导入会执行模块代码。
  • 不产生任何导入绑定。
  • 模块只执行一次且静态提升。

静态解析下的模块执行顺序

在 ESM 中,import 声明总是被提升到模块顶部,这种静态结构使得依赖图在代码执行前就完成链接。对 import './module' 而言,链接阶段不会建立任何导出绑定,但求值阶段仍会完整运行该模块的顶层代码。这意味着副作用在所有后续语句之前发生,无论它在文件中哪个位置写法。

模块的执行遵循深度优先顺序,每个模块只求值一次,缓存结果。如果多个导入语句引用同一个模块,第一个执行会触发求值,后续导入直接复用已完成的模块记录。因此纯副作用导入不会导致重复执行,但它会阻塞依赖它的模块——只有副作用模块代码运行完,当前模块才继续执行。

注册全局 hook 的初始化模块

假设有一个库 error-tracker.js,它需在应用启动时向 window 注入错误监听器并设置全局错误处理器,但其 API 不导出任何内容。在入口模块顶部写 import './error-tracker.js',就能保证该初始化代码先于业务代码执行,无需手动调用。

这种写法比动态 import() 更可靠,因为静态导入能被构建工具提前分析和优化,且执行顺序明确——在模块图遍历时就会触发。如果改用 commonjs 风格的 require 则无法在各环境中统一行为,而纯副作用导入是 ESM 标准的一部分。

依赖顺序与执行失败的边界

如果副作用模块依赖另一个模块的导出,但导入顺序不当,可能触发暂时性死区。比如在副作用模块中读取一个尚未初始化的 let 绑定,会抛 ReferenceError。这种问题在循环依赖中更常见,纯副作用导入可能让错误更隐蔽,因为看不到实际引用的值。

还有一点:静态的纯副作用导入无法条件执行。若只想在开发环境启用某个模块,必须使用动态 import() 配合标志判断,或者依赖打包器的替代机制。此外,若副作用模块顶层抛异常,整个模块图求值立即失败,后续模块不会执行。

回答前,多想一步

容易答错的地方

认为纯副作用导入不执行代码
错误。import './mod' 与普通导入一样会触发模块求值,只是不引入绑定。许多初学者误以为只有发生了引用的变量才会加载模块,实际上任何 import 声明都会让模块运行。
将纯副作用导入与动态 import 混淆
动态 import() 返回 Promise 且可异步、条件执行,而纯副作用导入是静态、无条件且阻塞后续。二者设计目标不同,前者需处理回调,后者在模块链接时统一处理。
试着用自己的话回答

面试官还会怎么问?

同一个模块既被纯副作用导入又被命名导入会执行两次吗?

不会。ESM 模块记录一旦求值完成,后续导入都会复用同一实例。纯副作用导入与命名导入在第一次出现时触发执行,之后导入只读取缓存,因此只执行一次。

纯副作用导入能导出绑定吗?它和 `import * as ns` 有何不同?

import './mod' 不创建任何绑定,而 import * as ns 会生成命名空间对象。后者用于访问导出值,前者纯粹为了副作用。若模块有导出但你想忽略它们,使用纯副作用导入是更明确的信号。

为什么构建工具能对纯副作用导入进行 tree-shaking?

有些打包器会假定纯副作用导入可被移除,但标准 ESM 并不保证。正确做法是在库的 package.json 中标注 sideEffects: false,否则直接删除会导致运行时错误,因为模块可能确实有依赖的环境操作。

从一道题,走向一组知识

把知识连起来

模块与语言机制

ESM 的 import 声明是否会被提升?这对代码执行顺序有何影响?

同属「模块与语言机制」专题,接着看 ESM import 声明提升与执行顺序 在具体场景中的处理方式。

模块与语言机制

如何使用 import 语法进行重命名导入,并且仍然绑定原模块的实时值?

同属「模块与语言机制」专题,接着看 ESM import 重命名导入 实时绑定 在具体场景中的处理方式。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • import

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 静态解析下的模块执行顺序
  3. 注册全局 hook 的初始化模块
  4. 依赖顺序与执行失败的边界
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑