
在 es 模块中,不能直接用 export const foo = foo 重声明已导入的同名标识符;需通过重命名导入(as)、命名导出语法(export { foo } from './foo')或显式赋值规避重复声明错误。
在 es 模块中,不能直接用 export const foo = foo 重声明已导入的同名标识符;需通过重命名导入(as)、命名导出语法(export { foo } from './foo')或显式赋值规避重复声明错误。
ES 模块(ESM)的静态解析特性要求所有导出标识符在模块顶层必须唯一且不可重复声明。当你写:
import { foo } from './foo';
export const foo = foo; // ❌ SyntaxError: Identifier 'foo' has already been declaredJavaScript 引擎会在解析阶段报错——因为 foo 已作为导入绑定存在,不能再以相同名称声明 const foo。
✅ 正确做法一:直接重导出(推荐,零开销)
若无需对导入值做任何处理,应使用重导出语法(re-export syntax),它不创建本地绑定,仅建立符号转发:
export { foo } from './foo';
export { bar } from './bar';这等价于在 ./foo.js 中定义 export const foo = ... 后,在当前模块对外透出同一引用,且无运行时开销、无命名冲突风险。
✅ 正确做法二:先导入、再导出(需本地操作)
若需在导出前对值执行逻辑(如日志、包装、条件处理),可先导入并重命名,再导出:
import { foo as importedFoo } from './foo';
import { bar as importedBar } from './bar';
// 可选:执行任意中间操作
console.log('Exporting foo...');
const wrappedFoo = () => {
console.time('foo execution');
const result = importedFoo();
console.timeEnd('foo execution');
return result;
};
export const foo = wrappedFoo;
export const bar = importedBar; // 直接导出亦可关键点:使用 as 为导入绑定起别名(如 importedFoo),彻底避免与导出名冲突。
⚠️ 注意事项
- 禁止混合使用同名导入与声明:import { x } from 'm'; const x = ... 或 export const x = x 均非法;
- export { x } from 'm' 不创建本地变量,因此不会触发命名冲突,性能最优;
- 若源模块导出的是 default,需用 export { default as foo } from './foo' 显式重命名;
- 在 Firebase Functions 等需严格组织函数入口的场景中,推荐优先采用重导出语法,既符合 ESM 规范,又保持与 CJS exports.foo = require('./foo').foo 的语义对等。
综上,根据是否需要中间处理选择对应策略:纯透传用 export { name } from 'path';需定制逻辑则用 import { name as localName } + export const name = ... 组合。

















