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

export ... from 再导出有哪几种写法?默认导出能被 export * 带出去吗?

export { a } from "./m.js" 把别的模块的导出直接转交出去,当前模块里不会多出变量 a。export * from "./m.js" 转交所有具名导出,但不包括 default,默认导出要单独写 export { default } from "./m.js" 或者改名成具名导出。

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

四种再导出写法

  1. export { a, b as c } from挑几个转交,可以改名
  2. export * from转交全部具名导出,不含 default
  3. export { default } from转交默认导出,常写成 default as Button

再导出同样是实时绑定。桶文件只是个转发层,底层模块的 let 导出后来被改了,经过桶文件导入的一方也能读到新值。

核心回答

先记住这个答案

export ... from 是把另一个模块的导出直接转交出去的写法,最常见于组件库的 index.js 桶文件。有四种形式:export { a, b as c } from 挑着转交并可改名,export * from 转交全部具名导出,export * as ns from 把整个模块打包成一个具名导出,export { default } from 转交默认导出。具名和默认的区别在于:export * 不会带上 default,默认导出必须单独写出来。另外再导出不会在当前模块里创建变量,当前文件想用还得自己再 import。

  • export * 不转发默认导出
  • 再导出不会在当前模块里创建变量,想用得另写 import
  • 两个 export * 有同名导出时,这个名字会被排除
  • export * as ns 把整个模块作为一个具名导出

一个组件库的桶文件

components/index.js 汇总各个组件,让使用方只从一个地方导入。

四种写法放在一起JavaScript
// components/index.js
export { default as Button } from './Button.js' // 默认导出改名成具名导出
export { default } from './Layout.js' // 继续作为本模块的默认导出
export * from './utils.js' // 全部具名导出,不含 default
export * as icons from './icons.js' // 使用方拿到 icons.Close、icons.Search
export { formatDate as format } from './date.js' // 挑一个并改名

// 下面这行会报 ReferenceError,再导出没有在这里创建变量
// console.log(Button)

使用方可以写 import Layout, { Button, format, icons } from "./components/index.js"。 注意最后被注释掉的那行。export { default as Button } from 只是声明了「对外有一个叫 Button 的导出,来源是那个文件」,并没有在 index.js 里声明变量。桶文件自己要用 Button,得另写一行 import Button from "./Button.js"。

export * 的两条特殊规则

export * 看起来是「全部转交」,实际上有两个例外,面试里经常被追问。

不含 default,同名会被排除
第一,它不包含 default。一个模块只能有一个默认导出,如果 export * 会带上 default,桶文件里写两个 export * 就会有两个默认导出,规范干脆把它排除了。 第二,两个 export * 来源里有同名的导出时,这个名字不会报错,而是被静默排除,两个都不导出。我在 Node.js 里实测,x1.js 和 x2.js 都导出了 dup,桶文件里各写一个 export *,import * as b 拿到的对象里没有 dup;如果使用方明确写 import { dup } from 这个桶文件,则会报 SyntaxError,提示有冲突的星号导出。 如果某个名字是当前模块自己显式导出的,或者用 export { dup } from 明确指定了来源,它的优先级高于 export *,不算冲突。
回答前,多想一步

容易答错的地方

以为 export * 把默认导出也带出去了
这是最常见的错误。组件文件用 export default 导出,桶文件只写 export * from "./Button.js",使用方怎么都导入不到 Button。要写成 export { default as Button } from "./Button.js"。
以为再导出等于先 import 再 export
效果接近,但再导出不会在当前模块作用域里留下变量。另外先 import 再 export 时,名字在当前模块里可见,写错了也更容易被 ESLint 发现,两者适合的场景不同。
试着用自己的话回答

面试官还会怎么问?

桶文件会影响 tree shaking 吗?

对 ESM 包来说,打包器能顺着再导出追踪到真正用到的模块,没用到的通常能删掉。问题出在副作用上:桶文件把几十个模块都拉进了依赖图,只要其中有模块被判定为有副作用,就删不掉。开发环境里还会让 Vite 这类工具多处理很多文件,所以大型项目会限制桶文件的使用范围。

export * as ns from 和先 import * as ns 再 export { ns } 一样吗?

对使用方来说结果一样,都拿到一个叫 ns 的命名空间对象。区别仍然是前者不在当前模块里创建 ns 变量。这个语法是 ES2020 才加入的,更早的代码只能用两行写法。

CommonJS 里怎么做再导出?

常见写法是 module.exports = { ...require("./a"), ...require("./b") },或者 exports.Button = require("./Button")。展开运算符是在那一刻复制属性值,不是实时绑定,底层模块后来改了导出,这边看不到。

从一道题,走向一组知识

把知识连起来

模块与语言机制

<script type="module"> 和普通 script 标签有哪些区别?

export 这类语法只能在模块脚本里用,普通 <script> 里出现就是语法错误。

模块与语言机制

import source 是什么?它和普通 import 有什么不一样?

再导出转交的是求值后的模块绑定,source phase import 拿的则是求值之前的模块源码对象。

参考资料

  • JavaScript:模块与语言机制参考资料

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

本题目录
  1. 先记住这个答案
  2. 一个组件库的桶文件
  3. export * 的两条特殊规则
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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