export

Baseline 已广泛支持

此功能已成熟,并可在许多设备和浏览器版本上运行。自 2018 年 5 月起,它已在各个浏览器中可用。

export 声明用于从 JavaScript 模块中导出值。导出的值可以通过 import 声明或动态导入导入到其他程序中。导入绑定的值可能会在导出它的模块中发生变化——当一个模块更新它导出的绑定值时,这个更新将在其导入的值中可见。

为了在源文件中使用 export 声明,运行时必须将该文件解释为模块。在 HTML 中,这可以通过在 <script> 标签中添加 type="module",或者被另一个模块导入来实现。模块会自动以严格模式解释。

语法

js
// Exporting declarations
export let name1, name2/*, … */; // also var
export const name1 = 1, name2 = 2/*, … */; // also var, let
export function functionName() { /* … */ }
export class ClassName { /* … */ }
export function* generatorFunctionName() { /* … */ }
export const { name1, name2: bar } = o;
export const [ name1, name2 ] = array;

// Export list
export { name1, /* …, */ nameN };
export { variable1 as name1, variable2 as name2, /* …, */ nameN };
export { variable1 as "string name" };
export { name1 as default /*, … */ };

// Default exports
export default expression;
export default function functionName() { /* … */ }
export default class ClassName { /* … */ }
export default function* generatorFunctionName() { /* … */ }
export default function () { /* … */ }
export default class { /* … */ }
export default function* () { /* … */ }

// Aggregating modules
export * from "module-name";
export * as name1 from "module-name";
export { name1, /* …, */ nameN } from "module-name";
export { import1 as name1, import2 as name2, /* …, */ nameN } from "module-name";
export { default, /* …, */ } from "module-name";
export { default as name1 } from "module-name";
nameN

要导出的标识符(以便可以通过另一个脚本中的import导入)。如果使用带 as 的别名,实际导出的名称可以指定为字符串字面量,这可能不是一个有效的标识符。

描述

每个模块可以有两种不同类型的导出:命名导出默认导出。每个模块可以有多个命名导出,但只能有一个默认导出。每种类型对应上述语法之一。

命名导出

js
// export features declared elsewhere
export { myFunction2, myVariable2 };

// export individual features (can export var, let,
// const, function, class)
export let myVariable = Math.sqrt(2);
export function myFunction() {
  // …
}

export 关键字之后,可以使用 letconstvar 声明,以及函数或类声明。还可以使用 export { name1, name2 } 语法导出在其他地方声明的名称列表。请注意,export {} 不会导出一个空对象——它是一个不执行任何操作的声明,不导出任何东西(一个空的名称列表)。

你不能在 usingawait using 声明上使用 export。但是,你可以导出已使用 usingawait using 在其他地方声明的变量。这样做仍然强烈不建议,因为变量一旦模块执行完毕就会被释放,导致所有导入者接收到一个已经释放的值。

js
export using resource1 = getResource(); // SyntaxError

// Allowed by syntax but discouraged
using resource2 = getResource();
export { resource2 };

导出声明不受暂时性死区规则的限制。你可以在名称 X 本身被声明之前声明模块导出 X

js
export { x };
const x = 1;
// This works, because `export` is only a declaration, but doesn't
// utilize the value of `x`.

默认导出

js
// export feature declared elsewhere as default
export { myFunction as default };
// This is equivalent to:
export default myFunction;

// export individual features as default
export default function () { /* … */ }
export default class { /* … */ }

注意:导出声明的名称必须彼此不同。如果存在名称重复的导出或使用多个 default 导出,将导致 SyntaxError 并阻止模块被评估。

export default 语法允许任何表达式。

js
export default 1 + 1;

作为特例,函数和类作为*声明*而不是表达式导出,并且这些声明可以是匿名的。这意味着函数会被提升。

js
// Works because `foo` is a function declaration,
// not a function expression
foo();

export default function foo() {
  console.log("Hi");
}

// It's still technically a declaration, but it's allowed
// to be anonymous
export default function () {
  console.log("Hi");
}

命名导出在需要导出多个值时很有用。导入此模块时,命名导出必须以完全相同的名称引用(可以选择使用 as 重命名),但默认导出可以以任何名称导入。例如

js
// file test.js
const k = 12;
export default k;
js
// some other file
import m from "./test"; // note that we have the freedom to use import m instead of import k, because k was default export

console.log(m); // 12

你也可以重命名命名导出以避免命名冲突

js
export { myFunction as function1, myVariable as variable };

你可以使用字符串字面量将名称重命名为不是有效标识符的内容。例如

js
export { myFunction as "my-function" };

重新导出 / 聚合

一个模块还可以“中继”从其他模块导出的值,而无需编写两个单独的 import/export 语句的麻烦。这通常在创建集中了各种模块的各种导出的单个模块(通常称为“桶模块”)时很有用。

这可以通过“export from”语法实现

js
export { default as function1, function2 } from "bar.js";

这类似于 import 和 export 的组合,不同之处在于 function1function2 在当前模块内部不可用

js
import { default as function1, function2 } from "bar.js";

export { function1, function2 };

大多数“import from”语法都有“export from”对应的语法。

js
export { x } from "mod";
export { x as v } from "mod";
export * as ns from "mod";

还有 export * from "mod",尽管没有 import * from "mod"。它将 mod 的所有命名导出重新导出为当前模块的命名导出,但 mod 的默认导出不被重新导出。如果存在两个通配符导出语句隐式地重新导出相同的名称,则两者都不会被重新导出。

js
// -- mod1.js --
export const a = 1;

// -- mod2.js --
export const a = 3;

// -- barrel.js --
export * from "./mod1.js";
export * from "./mod2.js";

// -- main.js --
import * as ns from "./barrel.js";

console.log(ns.a); // undefined

尝试直接导入重复的名称将抛出错误。

js
import { a } from "./barrel.js";
// SyntaxError: The requested module './barrel.js' contains conflicting star exports for name 'a'

尽管有其导入等价物,但以下语法是无效的

js
export DefaultExport from "bar.js"; // Invalid

正确的做法是重命名导出

js
export { default as DefaultExport } from "bar.js";

“export from”语法允许省略 as 标记,这使得默认导出仍作为默认导出重新导出。

js
export { default, function2 } from "bar.js";

export from 支持 import 支持的所有功能——例如,导入属性

js
export { default } from "./data.json" with { type: "json" };

示例

使用命名导出

在模块 my-module.js 中,我们可以包含以下代码

js
// module "my-module.js"
function cube(x) {
  return x * x * x;
}

const foo = Math.PI + Math.SQRT2;

const graph = {
  options: {
    color: "white",
    thickness: "2px",
  },
  draw() {
    console.log("From graph draw function");
  },
};

export { cube, foo, graph };

然后,在你的 HTML 页面中包含的顶级模块中,我们可以有

js
import { cube, foo, graph } from "./my-module.js";

graph.options = {
  color: "blue",
  thickness: "3px",
};

graph.draw(); // Logs "From graph draw function"
console.log(cube(3)); // 27
console.log(foo); // 4.555806215962888

以下几点需要注意

  • 你需要将此脚本包含在你的 HTML 中,使用 type="module"<script> 元素,以便它被识别为模块并得到适当处理。
  • 你不能通过 file:// URL 运行 JS 模块——你会遇到 CORS 错误。你需要通过 HTTP 服务器运行它。

使用默认导出

如果我们要导出代表整个模块的单个值,我们可以使用默认导出

js
// module "cube.js"

export default function cube(x) {
  return x * x * x;
}

然后,在另一个脚本中,导入默认导出非常简单

js
import cube from "./cube.js";

console.log(cube(3)); // 27

使用 export from

让我们举一个例子,我们有以下层次结构

  • childModule1.js: 导出 myFunctionmyVariable
  • childModule2.js: 导出 MyClass
  • parentModule.js: 作为聚合器(不执行其他操作)
  • 顶级模块:消费 parentModule.js 的导出

代码片段如下所示

js
// In childModule1.js
function myFunction() {
  console.log("Hello!");
}
const myVariable = 1;
export { myFunction, myVariable };
js
// In childModule2.js
class MyClass {
  constructor(x) {
    this.x = x;
  }
}

export { MyClass };
js
// In parentModule.js
// Only aggregating the exports from childModule1 and childModule2
// to re-export them
export { myFunction, myVariable } from "childModule1.js";
export { MyClass } from "childModule2.js";
js
// In top-level module
// We can consume the exports from a single module since parentModule
// "collected"/"bundled" them in a single source
import { myFunction, myVariable, MyClass } from "parentModule.js";

规范

规范
ECMAScript® 2026 语言规范
# sec-exports

浏览器兼容性

另见