为什么不使用 export default 详细说明

一般项目中推荐使用 export,而非 export default

虽然提供的资料解释了 export default(默认导出)和 named exports(命名导出)的用法,但并没有直接说明“为什么不推荐使用 export default”。实际上,是否推荐使用 export default 是一个在 JavaScript 社区中存在不同观点的话题,它并非绝对被“不推荐”,而是各有优缺点。

不过,确实有一些开发者和风格指南倾向于更少使用或不使用 export default,主要基于以下原因:

  1. 破坏了静态分析和摇树优化 (Tree Shaking): export default 导出一个模块的“主要”值,而这个值可能是一个包含多个方法或组件的对象。这使得工具(如 Webpack)更难精确地识别和移除未使用的代码,因为需要导入整个默认对象才能访问其属性。
  2. 增加了重构的难度和出错风险: 导入时的名称可以是任意的,与导出时的名称无关。这虽然提供了灵活性,但也意味着如果导出的模块重命名了其内部的函数或变量,所有使用默认导入的地方都需要手动更新,IDE 的自动重命名功能可能无法准确追踪到导入处的名称。
  3. 降低了代码的可读性和可发现性: 使用 import * as something from './module' 或命名导入可以清楚地看到一个模块提供了哪些 API。而 import something from './module' 则需要开发者去源文件查看 something 到底是什么,降低了代码的直观性。

代码示例对比:

使用 export default (潜在问题):

// mathUtils.js
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;

// 将包含多个函数的对象作为默认导出
const mathOperations = { add, subtract, multiply };
export default mathOperations;

// main.js
// 导入时名称可以随意 (这里是 'utils')
import utils from './mathUtils';

// 问题:如果 mathUtils.js 中 mathOperations 对象被重命名,这里需要手动更新。
// 问题:如果只用到 'add',整个 utils 对象可能被引入,不利于摇树优化。
console.log(utils.add(2, 3)); // 5
console.log(utils.subtract(5, 2)); // 3

使用 Named Exports (推荐):

// mathUtils.js
// 直接导出各个函数
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;

// main.js
// 只导入需要的函数,名称必须与导出时一致(除非使用 'as' 重命名)
import { add, subtract } from './mathUtils';

// 优点:如果 add 函数在 mathUtils.js 中被重命名,现代 IDE 可以自动更新这里的导入。
// 优点:明确知道导入了什么。
// 优点:工具可以更容易地进行摇树优化,因为它知道只使用了 'add' 和 'subtract','multiply' 可以被安全地移除。
console.log(add(2, 3)); // 5
console.log(subtract(5, 2)); // 3

总结来说,倾向于不使用 export default 的观点主要是为了提高代码的可维护性、可读性,并更好地支持现代构建工具的优化(如摇树优化)。Named Exports 提供了更明确、更安全的模块交互方式。但这并不意味着 export default 是错误的,对于导出一个单一的主要值(如 React 组件)的场景,它仍然是一个有效的选择。