import
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.
静态 import
声明用于导入只读的活动 bindings,这是另一个模块的 exported。导入的绑定称为实时绑定,因为它们由导出绑定的模块更新,但不能由导入模块重新分配。
¥The static import
declaration is used to import read-only live bindings which are exported by another module. The imported bindings are called live bindings because they are updated by the module that exported the binding, but cannot be re-assigned by the importing module.
为了在源文件中使用 import
声明,运行时必须将该文件解释为 module。在 HTML 中,这是通过将 type="module"
添加到 <script>
标记来完成的。模块在 严格模式 中自动解释。
¥In order to use the import
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. Modules are automatically interpreted in strict mode.
还有一个类似函数的动态 import()
,不需要 type="module"
的脚本。
¥There is also a function-like dynamic import()
, which does not require scripts of type="module"
.
语法
¥Syntax
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { default as alias } from "module-name";
import { export1, export2 } from "module-name";
import { export1, export2 as alias2, /* … */ } from "module-name";
import { "string name" as alias } from "module-name";
import defaultExport, { export1, /* … */ } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
defaultExport
-
引用模块默认导出的名称。必须是有效的 JavaScript 标识符。
module-name
-
要从中导入的模块。说明符的评估是由主机指定的。这通常是包含该模块的
.js
文件的相对或绝对 URL。在 Node 中,无扩展导入通常引用node_modules
中的包。某些打包程序可能允许导入不带扩展名的文件;检查你的环境。只允许使用单引号和双引号字符串。 name
-
引用导入时将用作一种命名空间的模块对象的名称。必须是有效的 JavaScript 标识符。
exportN
-
要导入的出口名称。该名称可以是标识符或字符串文字,具体取决于
module-name
声明要导出的内容。如果它是字符串文字,则必须将其别名为有效标识符。 aliasN
-
将引用命名导入的名称。必须是有效的 JavaScript 标识符。
描述
¥Description
import
声明只能出现在模块中,并且只能出现在顶层(即不能出现在块、函数等内部)。如果在非模块上下文中遇到 import
声明(例如,没有 type="module"
、eval
、new Function
的 <script>
标记,它们都以 "script" 或 "函数体" 作为解析目标),则会抛出 SyntaxError
。要在非模块上下文中加载模块,请改用 动态导入 语法。
¥import
declarations can only be present in modules, and only at the top-level (i.e. not inside blocks, functions, etc.). If an import
declaration is encountered in non-module contexts (for example, <script>
tags without type="module"
, eval
, new Function
, which all have "script" or "function body" as parsing goals), a SyntaxError
is thrown. To load modules in non-module contexts, use the dynamic import syntax instead.
所有导入的绑定不能与任何其他声明位于同一范围内,包括 let
、const
、class
、function
、var
和 import
声明。
¥All imported bindings cannot be in the same scope as any other declaration, including let
, const
, class
, function
, var
, and import
declaration.
import
声明被设计为语法严格(例如,仅字符串文字说明符,仅允许在顶层,所有绑定必须是标识符),这允许在评估模块之前对模块进行静态分析和链接。这是使模块本质上异步的关键,为 顶层等待 等功能提供支持。
¥import
declarations are designed to be syntactically rigid (for example, only string literal specifiers, only permitted at the top-level, all bindings must be identifiers), which allows modules to be statically analyzed and linked before getting evaluated. This is the key to making modules asynchronous by nature, powering features like top-level await.
导入报关表格
¥Forms of import declarations
import
声明有四种形式:
¥There are four forms of import
declarations:
- 命名导入:
import { export1, export2 } from "module-name";
- 默认导入:
import defaultExport from "module-name";
- 命名空间导入:
import * as name from "module-name";
- 副作用导入:
import "module-name";
下面是阐明语法的示例。
¥Below are examples to clarify the syntax.
命名导入
¥Named import
给定一个名为 myExport
的值,该值已从模块 my-module
隐式导出为 export * from "another.js"
或显式使用 export
语句,这会将 myExport
插入到当前作用域中。
¥Given a value named myExport
which has been exported from the module my-module
either implicitly as export * from "another.js"
or explicitly using the export
statement, this inserts myExport
into the current scope.
import { myExport } from "/modules/my-module.js";
你可以从同一模块导入多个名称。
¥You can import multiple names from the same module.
import { foo, bar } from "/modules/my-module.js";
你可以在导入时重命名导出。例如,这会将 shortName
插入到当前作用域中。
¥You can rename an export when importing it. For example, this inserts shortName
into the current scope.
import { reallyReallyLongModuleExportName as shortName } from "/modules/my-module.js";
模块还可以将成员导出为字符串文字,这不是有效的标识符,在这种情况下,你必须为其指定别名才能在当前模块中使用它。
¥A module may also export a member as a string literal which is not a valid identifier, in which case you must alias it in order to use it in the current module.
// /modules/my-module.js
const a = 1;
export { a as "a-b" };
import { "a-b" as a } from "/modules/my-module.js";
注意:
import { x, y } from "mod"
不等于import defaultExport from "mod"
然后从defaultExport
解构x
和y
。命名导入和默认导入是 JavaScript 模块中不同的语法。¥Note:
import { x, y } from "mod"
is not equivalent toimport defaultExport from "mod"
and then destructuringx
andy
fromdefaultExport
. Named and default imports are distinct syntaxes in JavaScript modules.
默认导入
¥Default import
默认导出需要使用相应的默认导入语法进行导入。最简单的版本直接导入默认的:
¥Default exports need to be imported with the corresponding default import syntax. The simplest version directly imports the default:
import myDefault from "/modules/my-module.js";
由于默认导出没有显式指定名称,因此你可以为标识符指定任何你喜欢的名称。
¥Since the default export doesn't explicitly specify a name, you can give the identifier any name you like.
还可以使用命名空间导入或命名导入来指定默认导入。在这种情况下,必须首先声明默认导入。例如:
¥It is also possible to specify a default import with namespace imports or named imports. In such cases, the default import will have to be declared first. For instance:
import myDefault, * as myModule from "/modules/my-module.js";
// myModule.default and myDefault point to the same binding
or
import myDefault, { foo, bar } from "/modules/my-module.js";
导入名为 default
的名称与默认导入具有相同的效果。由于 default
是保留字,因此需要为该名称起别名。
¥Importing a name called default
has the same effect as a default import. It is necessary to alias the name because default
is a reserved word.
import { default as myDefault } from "/modules/my-module.js";
命名空间导入
¥Namespace import
以下代码将 myModule
插入到当前作用域中,其中包含来自位于 /modules/my-module.js
的模块的所有导出。
¥The following code inserts myModule
into the current scope, containing all the exports from the module located at /modules/my-module.js
.
import * as myModule from "/modules/my-module.js";
这里,myModule
代表一个命名空间对象,其中包含所有导出作为属性。例如,如果上面导入的模块包含导出 doAllTheAmazingThings()
,你可以这样调用它:
¥Here, myModule
represents a namespace object which contains all exports as properties. For example, if the module imported above includes an export doAllTheAmazingThings()
, you would call it like this:
myModule.doAllTheAmazingThings();
myModule
是带有 null
原型机 的 sealed 对象。默认导出可作为名为 default
的键使用。欲了解更多信息,请参阅 模块命名空间对象。
¥myModule
is a sealed object with null
prototype. The default export available as a key called default
. For more information, see module namespace object.
注意:JavaScript 没有像
import * from "module-name"
这样的通配符导入,因为名称冲突的可能性很高。¥Note: JavaScript does not have wildcard imports like
import * from "module-name"
, because of the high possibility of name conflicts.
导入模块仅用于其副作用
¥Import a module for its side effects only
导入整个模块只是为了产生副作用,而不导入任何内容。这会运行模块的全局代码,但实际上并不导入任何值。
¥Import an entire module for side effects only, without importing anything. This runs the module's global code, but doesn't actually import any values.
import "/modules/my-module.js";
这通常用于 polyfills,它会改变全局变量。
¥This is often used for polyfills, which mutate the global variables.
提升
¥Hoisting
导入报关单为 hoisted。在这种情况下,这意味着导入引入的标识符在整个模块范围内可用,并且它们的副作用是在模块的其余代码运行之前产生的。
¥Import declarations are hoisted. In this case, that means that the identifiers the imports introduce are available in the entire module scope, and their side effects are produced before the rest of the module's code runs.
myModule.doAllTheAmazingThings(); // myModule.doAllTheAmazingThings is imported by the next line
import * as myModule from "/modules/my-module.js";
示例
标准导入
¥Standard Import
在此示例中,我们创建一个可重用模块,该模块导出一个函数以获取给定范围内的所有素数。
¥In this example, we create a re-usable module that exports a function to get all primes within a given range.
// getPrimes.js
/**
* Returns a list of prime numbers that are smaller than `max`.
*/
export function getPrimes(max) {
const isPrime = Array.from({ length: max }, () => true);
isPrime[0] = isPrime[1] = false;
isPrime[2] = true;
for (let i = 2; i * i < max; i++) {
if (isPrime[i]) {
for (let j = i ** 2; j < max; j += i) {
isPrime[j] = false;
}
}
}
return [...isPrime.entries()]
.filter(([, isPrime]) => isPrime)
.map(([number]) => number);
}
import { getPrimes } from "/modules/getPrimes.js";
console.log(getPrimes(10)); // [2, 3, 5, 7]
导入的值只能由导出者修改
¥Imported values can only be modified by the exporter
导入的标识符是实时绑定,因为导出它的模块可能会重新分配它,并且导入的值会改变。但是,导入它的模块无法重新分配它。尽管如此,任何持有导出对象的模块都可以改变该对象,并且导入相同值的所有其他模块都可以观察到改变的值。
¥The identifier being imported is a live binding, because the module exporting it may re-assign it and the imported value would change. However, the module importing it cannot re-assign it. Still, any module holding an exported object can mutate the object, and the mutated value can be observed by all other modules importing the same value.
你还可以通过 模块命名空间对象 观察新值。
¥You can also observe the new value through the module namespace object.
// my-module.js
export let myValue = 1;
setTimeout(() => {
myValue = 2;
}, 500);
// main.js
import { myValue } from "/modules/my-module.js";
import * as myModule from "/modules/my-module.js";
console.log(myValue); // 1
console.log(myModule.myValue); // 1
setTimeout(() => {
console.log(myValue); // 2; my-module has updated its value
console.log(myModule.myValue); // 2
myValue = 3; // TypeError: Assignment to constant variable.
// The importing module can only read the value but can't re-assign it.
}, 1000);
规范
Specification |
---|
ECMAScript Language Specification # sec-imports |
浏览器兼容性
BCD tables only load in the browser
也可以看看
¥See also
export
import()
import.meta
- blogs.windows.com 上的 预览 ES2015、ES2016 及更高版本的 ES6 模块及更多内容 (2016)
- hacks.mozilla.org 上的 ES6 深入研究:模块 (2015)
- hacks.mozilla.org 上的 ES 模块:卡通深潜 (2018)
- 探索 JS,第 16 章:模块 博士阿克塞尔·劳施梅尔
- javascript.info 上的 导出和导入