export
Baseline Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since May 2018.
export
声明用于从 JavaScript 模块导出值。然后可以使用 import
声明或 动态导入 将导出的值导入到其他程序中。导入的绑定的值可能会在导出它的模块中发生更改 - 当模块更新其导出的绑定的值时,更新将在其导入的值中可见。
¥The export
declaration is used to export values from a JavaScript module. Exported values can then be imported into other programs with the import
declaration or dynamic import. The value of an imported binding is subject to change in the module that exports it — when a module updates the value of a binding that it exports, the update will be visible in its imported value.
为了在源文件中使用 export
声明,运行时必须将该文件解释为 module。在 HTML 中,这是通过将 type="module"
添加到 <script>
标记或由另一个模块导入来完成的。模块在 严格模式 中自动解释。
¥In order to use the export
declaration in a source file, the file must be interpreted by the runtime as a module. In HTML, this is done by adding type="module"
to the <script>
tag, or by being imported by another module. Modules are automatically interpreted in strict mode.
语法
¥Syntax
// 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";
描述
¥Description
每个模块可以有两种不同类型的导出,命名导出和默认导出。每个模块可以有多个命名导出,但只能有一个默认导出。每种类型对应于上述语法之一。
¥Every module can have two different types of export, named export and default export. You can have multiple named exports per module but only one default export. Each type corresponds to one of the above syntax.
命名导出:
¥Named exports:
// 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
关键字之后,可以使用 let
、const
和 var
声明,以及函数或类声明。你还可以使用 export { name1, name2 }
语法导出在其他地方声明的名称列表。请注意,export {}
不导出空对象 - 它是一个不导出任何内容的无操作声明(空名称列表)。
¥After the export
keyword, you can use let
, const
, and var
declarations, as well as function or class declarations. You can also use the export { name1, name2 }
syntax to export a list of names declared elsewhere. Note that export {}
does not export an empty object — it's a no-op declaration that exports nothing (an empty name list).
出口报关不受 颞死区 规则的约束。你可以在声明名称 X
本身之前声明模块导出 X
。
¥Export declarations are not subject to temporal dead zone rules. You can declare that the module exports X
before the name X
itself is declared.
export { x };
const x = 1;
// This works, because `export` is only a declaration, but doesn't
// utilize the value of `x`.
默认导出:
¥Default exports:
// 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
并阻止评估模块。¥Note: Names for export declarations must be distinct from each other. Having exports with duplicate names or using more than one
default
export will result in aSyntaxError
and prevent the module from being evaluated.
export default
语法允许任何表达式。
¥The export default
syntax allows any expression.
export default 1 + 1;
作为一种特殊情况,函数和类被导出为声明,而不是表达式,并且这些声明可以是匿名的。这意味着功能将被提升。
¥As a special case, functions and classes are exported as declarations, not expressions, and these declarations can be anonymous. This means functions will be hoisted.
// 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
重命名),但可以使用任何名称导入默认导出。例如:
¥Named exports are useful when you need to export several values. When importing this module, named exports must be referred to by the exact same name (optionally renaming it with as
), but the default export can be imported with any name. For example:
// file test.js
const k = 12;
export default k;
// 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
你还可以重命名命名导出以避免命名冲突:
¥You can also rename named exports to avoid naming conflicts:
export { myFunction as function1, myVariable as variable };
你可以使用字符串文字将名称重命名为无效标识符。例如:
¥You can rename a name to something that's not a valid identifier by using a string literal. For example:
export { myFunction as "my-function" };
再出口/聚合
¥Re-exporting / Aggregating
模块还可以从其他模块导出 "relay" 值,而无需编写两个单独的导入/导出语句。当创建集中来自各个模块(通常称为 "枪管模块")的各种导出的单个模块时,这通常很有用。
¥A module can also "relay" values exported from other modules without the hassle of writing two separate import/export statements. This is often useful when creating a single module concentrating various exports from various modules (usually called a "barrel module").
这可以通过 "出口自" 语法来实现:
¥This can be achieved with the "export from" syntax:
export { default as function1, function2 } from "bar.js";
这相当于导入和导出的组合,只是 function1
和 function2
在当前模块内不可用:
¥Which is comparable to a combination of import and export, except that function1
and function2
do not become available inside the current module:
import { default as function1, function2 } from "bar.js";
export { function1, function2 };
大多数 "导入于" 语法都有 "出口自" 对应项。
¥Most of the "import from" syntaxes have "export from" counterparts.
export { x } from "mod";
export { x as v } from "mod";
export * as ns from "mod";
还有 export * from "mod"
,虽然没有 import * from "mod"
。这会将 mod
中的所有命名导出重新导出为当前模块的命名导出,但 mod
的默认导出不会重新导出。如果存在两个隐式重新导出相同名称的通配符导出语句,则两者都不会重新导出。
¥There is also export * from "mod"
, although there's no import * from "mod"
. This re-exports all named exports from mod
as the named exports of the current module, but the default export of mod
is not re-exported. If there are two wildcard exports statements that implicitly re-export the same name, neither one is re-exported.
// -- 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
尝试直接导入重复的名称将引发错误。
¥Attempting to import the duplicate name directly will throw an error.
import { a } from "./barrel.js";
// SyntaxError: The requested module './barrel.js' contains conflicting star exports for name 'a'
尽管具有等效的导入功能,但以下内容在语法上无效:
¥The following is syntactically invalid despite its import equivalent:
export DefaultExport from "bar.js"; // Invalid
正确的方法是重命名导出:
¥The correct way of doing this is to rename the export:
export { default as DefaultExport } from "bar.js";
"出口自" 语法允许省略 as
标记,这使得默认导出仍会重新导出为默认导出。
¥The "export from" syntax allows the as
token to be omitted, which makes the default export still re-exported as default export.
export { default, function2 } from "bar.js";
示例
使用命名导出
¥Using named exports
在模块 my-module.js
中,我们可以包含以下代码:
¥In a module my-module.js
, we could include the following code:
// 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 页面中包含的顶层模块中,我们可以:
¥Then in the top-level module included in your HTML page, we could have:
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
重要的是要注意以下几点:
¥It is important to note the following:
使用默认导出
¥Using the default export
如果我们想导出单个值或为你的模块提供后备值,你可以使用默认导出:
¥If we want to export a single value or to have a fallback value for your module, you could use a default export:
// module "my-module.js"
export default function cube(x) {
return x * x * x;
}
然后,在另一个脚本中,可以直接导入默认导出:
¥Then, in another script, it is straightforward to import the default export:
import cube from "./my-module.js";
console.log(cube(3)); // 27
使用导出自
¥Using export from
让我们举一个具有以下层次结构的示例:
¥Let's take an example where we have the following hierarchy:
childModule1.js
:导出myFunction
和myVariable
childModule2.js
:正在导出MyClass
parentModule.js
:充当聚合者(不做任何其他事情)- 顶层模块:消耗
parentModule.js
的出口
使用代码片段会是这样的:
¥This is what it would look like using code snippets:
// In childModule1.js
function myFunction() {
console.log("Hello!");
}
const myVariable = 1;
export { myFunction, myVariable };
// In childModule2.js
class MyClass {
constructor(x) {
this.x = x;
}
}
export { MyClass };
// 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";
// 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";
规范
Specification |
---|
ECMAScript Language Specification # sec-exports |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also
import
- JavaScript 模块 指南
- hacks.mozilla.org 上的 ES6 深入研究:模块 (2015)
- hacks.mozilla.org 上的 ES 模块:卡通深潜 (2018)
- 探索 JS,第 16 章:模块 博士阿克塞尔·劳施梅尔