显式声明依赖可提升执行效率与可维护性:esm 通过静态 import 在解析阶段确定绑定位置,避免运行时查找;命名导入支持 tree-shaking 且无属性访问开销;动态 import 削弱静态分析能力;路径别名和 exports 映射可固化依赖路径、加速模块加载。

直接在模块路径下声明显式依赖,能避免 JavaScript 引擎在运行时沿作用域链逐层查找变量,从而减少查找开销、提升执行效率,并增强代码可维护性。
明确导入所需符号,避免隐式全局或上下文推导
ES 模块(ESM)要求所有外部引用必须通过 import 显式声明。这不仅让依赖关系一目了然,更关键的是:引擎在解析阶段就能确定变量绑定位置,无需在执行时动态搜索 globalThis、闭包外层或 this 上下文。
- ✅ 正确:用
import { debounce } from 'lodash-es'—— 绑定在当前模块的词法环境中,访问即直达 - ❌ 避免:通过
const debounce = window._.debounce或require('lodash').debounce(CommonJS 动态调用)—— 触发属性访问、可能跨对象查找,且无法被静态分析优化
优先使用命名导入而非默认导入 + 属性访问
当模块导出多个函数时,用命名导入可让构建工具(如 Rollup、esbuild)做更精准的 tree-shaking,同时避免运行时对象属性查找。
- ✅ 推荐:
import { map, filter } from 'ramda'→ 编译后直接绑定到局部变量,调用无属性访问开销 - ⚠️ 谨慎:
import R from 'ramda'; R.map(...)→ 每次调用都需解析R对象并查找map属性,多一层原型链或自有属性检索
避免在模块顶层使用动态 require 或 import()
动态导入返回 Promise,其模块标识符在运行时才确定,导致依赖无法静态解析,变量绑定延迟到加载完成,丧失词法作用域优势。
- 静态
import:路径是字符串字面量,打包器可提前分析、内联、重命名,变量访问路径固定 - 动态
import('./utils.js'):路径可能拼接,引擎无法预知导出内容,每次调用都要重新解析模块、建立新绑定,增加运行时开销 - 若必须动态加载,尽量将后续逻辑封装在回调中,避免在模块顶层反复触发查找
利用构建工具的“导出映射”和“精确路径别名”固化依赖路径
在 package.json 中配置 "exports" 或使用 Vite/Webpack 的 resolve.alias,可确保模块路径唯一、稳定。这能防止因路径歧义导致多重解析或循环查找。
- 例如将
import 'utils'映射到./src/lib/utils.mjs,避免 Node.js 的多级node_modules查找流程 - 路径越确定,模块加载越快,变量绑定越早完成,运行时就少一次“去哪里找这个模块”的决策










