ES6 模块化(ES Module)是现代前端构建工具的基础。webpack 和 Vite 依赖这套规范来进行静态分析和 tree shaking。理解 exportimport 的各种变体,对日常开发很有帮助。

命名导出与命名导入

// a.js —— 分别导出
export function fn() {
  console.log('fn');
}
export const name = 'a';
export const obj = { name: 'zhangsan' };
 
// 或统一导出(推荐:一眼看清模块暴露了什么)
function fn() {
  console.log('fn');
}
const name = 'a';
const obj = { name: 'zhangsan' };
export { fn, name, obj };
// b.js —— 命名导入
import { fn, name, obj } from './a';
 
fn();
console.log(name);
console.log(obj);
 
// 重命名导入(避免命名冲突)
import { fn as myFn } from './a';
 
// 全部导入为一个命名空间对象
import * as a from './a';
a.fn();
console.log(a.name);

默认导出与默认导入

每个模块只能有一个默认导出:

// a.js
const utils = { fn() {}, name: 'a' };
export default utils;
// b.js
// 默认导入可以任意命名
import utils from './a';
console.log(utils.name);

默认导出和命名导出可以共存:

import utils, { name } from './a';

导出重命名、聚合导出

// 导出时重命名
export { fn as myFn, name as moduleName };
 
// 聚合导出:从其他模块导入后立即导出
// 常用于 barrel 模式——一个 index.js 统一导出所有子模块
export { fn, name } from './a';
export { default as Comp } from './Comp';
 
// 全部聚合
export * from './a'; // 导出所有命名导出
export { default } from './a'; // 导出默认导出

两种导出方式对比

特性命名导出默认导出
数量多个一个
导入语法import { a, b } from './m'import x from './m'
重命名import { a as b }导入时任意命名
适用场景工具函数库、多变量组件、类、单例、主要功能
Tree Shaking✅ 支持支持(但导入整个默认对象时会有困难)

一个模块里可以同时使用两者,但这通常让使用者困惑。一般选择一种风格贯穿一个项目。

动态导入

import() 返回 Promise,按需加载模块(代码分割的基础):

// 条件加载
if (needFeature) {
  const module = await import('./heavy-feature.js');
  module.init();
}
 
// 路由懒加载(React/Vue 常见模式)
const Dashboard = () => import('./pages/Dashboard.vue');

import.meta

ES 模块中可以访问 import.meta 获取模块元信息:

// 当前模块的 URL
console.log(import.meta.url);
 
// Vite 环境变量
console.log(import.meta.env.VITE_API_URL);

ES Module 与 CommonJS 对比

特性ES ModuleCommonJS (Node)
语法import / exportrequire / module.exports
加载时机编译时静态分析运行时动态加载
是否同步异步(浏览器)同步(服务端)
Tree Shaking
this 指向undefined当前模块对象
循环引用可以处理(但值是引用,可能为 undefined)可以处理(返回已执行的部分)

在 ES Module 中 this === undefined,而在 CommonJS 中 this === module.exports。这是一个常见的面试细节。

相关笔记