import
Baseline 廣泛可用 *
靜態的 import 宣告用於匯入由另一個模組匯出的只讀的即時繫結。匯入的繫結被稱為即時繫結,因為它們由匯出該繫結的模組更新,但不能被匯入模組重新賦值。
為了在原始檔中使用 import 宣告,執行時必須將該檔案解釋為模組。在 HTML 中,這是透過向 <script> 標籤新增 type="module" 來實現的。模組會自動在嚴格模式下解釋。
還有一種類似函式的動態 import(),它不需要 type="module" 指令碼。
語法
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-
要匯入的模組。只允許使用單引號和雙引號的字串字面量。指定符的評估由宿主指定。大多數宿主與瀏覽器保持一致,將指定符解析為相對於當前模組 URL 的 URL(參見
import.meta.url)。Node、打包工具和其他非瀏覽器環境通常在此基礎上定義自己的功能,因此您應該查閱它們的文件以瞭解確切的規則。模組說明符解析部分也有更多資訊。 name-
模組物件的名稱,在引用匯入時將用作一種名稱空間。必須是有效的 JavaScript 識別符號。
exportN-
要匯入的匯出名稱。名稱可以是識別符號或字串字面量,具體取決於
module-name宣告要匯出的內容。如果它是字串字面量,則必須將其別名為有效的識別符號。 aliasN-
將引用命名匯入的名稱。必須是有效的 JavaScript 識別符號。
"module-name" 後面可以跟一組匯入屬性,以 with 關鍵字開頭。
描述
import 宣告只能出現在模組中,並且只能在頂層(即,不能在塊、函式等內部)。如果在非模組上下文(例如,沒有 type="module" 的 <script> 標籤、eval、new Function,它們都將“指令碼”或“函式體”作為解析目標)中遇到 import 宣告,則會丟擲 SyntaxError。要在非模組上下文中載入模組,請改用動態匯入語法。
所有匯入的繫結不能與任何其他宣告處於同一作用域,包括 let、const、class、function、var 和 import 宣告。
import 宣告被設計為語法嚴格(例如,只允許字串字面量指定符,只允許在頂層使用,所有繫結必須是識別符號),這允許模組在評估之前進行靜態分析和連結。這是使模組本質上非同步的關鍵,並支援頂層 await 等功能。
匯入宣告的形式
有四種形式的 import 宣告
- 命名匯入:
import { export1, export2 } from "module-name"; - 預設匯入:
import defaultExport from "module-name"; - 名稱空間匯入:
import * as name from "module-name"; - 副作用匯入:
import "module-name";
以下示例旨在闡明語法。
命名匯入
給定一個名為 myExport 的值,它已從模組 my-module 隱式地作為 export * from "another.js" 或顯式地使用 export 語句匯出,這會將 myExport 插入當前作用域。
import { myExport } from "/modules/my-module.js";
您可以從同一個模組匯入多個名稱。
import { foo, bar } from "/modules/my-module.js";
您可以在匯入時重新命名匯出。例如,這會將 shortName 插入當前作用域。
import { reallyReallyLongModuleExportName as shortName } from "/modules/my-module.js";
模組還可以將成員作為字串字面量匯出,該字串字面量不是有效的識別符號,在這種情況下,您必須將其別名化才能在當前模組中使用。
// /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 模組中是不同的語法。
預設匯入
預設匯出需要使用相應的預設匯入語法進行匯入。此版本直接匯入預設值。
import myDefault from "/modules/my-module.js";
由於預設匯出沒有顯式指定名稱,因此您可以為識別符號指定任何您喜歡的名稱。
還可以使用名稱空間匯入或命名匯入來指定預設匯入。在這種情況下,預設匯入必須首先宣告。例如:
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 是一個保留字,因此需要將其別名化。
import { default as myDefault } from "/modules/my-module.js";
名稱空間匯入
以下程式碼將 myModule 插入當前作用域,其中包含來自 /modules/my-module.js 模組的所有匯出。
import * as myModule from "/modules/my-module.js";
在這裡,myModule 代表一個名稱空間物件,其中包含所有匯出作為屬性。例如,如果上面匯入的模組包含匯出 doAllTheAmazingThings(),您將像這樣呼叫它:
myModule.doAllTheAmazingThings();
myModule 是一個 密封 物件,具有 null 原型。預設匯出以名為 default 的鍵的形式提供。有關更多資訊,請參閱模組名稱空間物件。
注意: JavaScript 沒有像 import * from "module-name" 這樣的萬用字元匯入,因為名稱衝突的可能性很高。
只為副作用匯入模組
只為副作用匯入整個模組,而不匯入任何內容。這會執行模組的全域性程式碼,但實際上不匯入任何值。
import "/modules/my-module.js";
這通常用於polyfill,它們會修改全域性變數。
提升
匯入宣告是提升的。在這種情況下,這意味著匯入引入的識別符號在整個模組作用域中都可用,並且它們的副作用在模組的其餘程式碼執行之前產生。
myModule.doAllTheAmazingThings(); // myModule.doAllTheAmazingThings is imported by the next line
import * as myModule from "/modules/my-module.js";
模組指定符解析
ECMAScript 規範沒有定義模組指定符如何解析,並將其留給宿主環境(例如,瀏覽器、Node.js、Deno)。瀏覽器行為由HTML 規範指定,這已成為所有環境的事實標準。
HTML 規範、Node 和許多其他規範都廣泛識別三種類型的指定符:
- 以
/、./或../開頭的相對指定符,它們相對於當前模組 URL 解析。 - 可解析為 URL 的絕對指定符,它們按原樣解析。
- 不是上述任何一種的裸指定符。
相對指定符最值得注意的注意事項,特別是對於熟悉 CommonJS 約定的人來說,是瀏覽器禁止一個指定符隱式解析為許多潛在的候選。在 CommonJS 中,如果您有 main.js 和 utils/index.js,那麼以下所有內容都將從 utils/index.js 匯入“預設匯出”:
// main.js
const utils = require("./utils"); // Omit the "index.js" file name
const utils = require("./utils/index"); // Omit only the ".js" extension
const utils = require("./utils/index.js"); // The most explicit form
在 Web 上,這代價很高,因為如果您編寫 import x from "./utils",瀏覽器需要向 utils、utils/index.js、utils.js 以及可能許多其他 URL 傳送請求,直到找到可匯入的模組。因此,在 HTML 規範中,指定符預設只能是相對於當前模組 URL 解析的 URL。您不能省略副檔名或 index.js 檔名。此行為已由 Node 的 ESM 實現繼承,但它不是 ECMAScript 規範的一部分。
請注意,這並不意味著 import x from "./utils" 在 Web 上永遠不起作用。瀏覽器仍然會向該 URL 傳送請求,如果伺服器能返回正確的內容,匯入就會成功。這要求伺服器實現一些自定義解析邏輯,因為通常沒有副檔名的請求被理解為 HTML 檔案的請求。
絕對指定符可以是任何型別的URL,可解析為可匯入的原始碼。最值得注意的是:
-
HTTP URL 在 Web 上始終受支援,因為大多數指令碼已經具有 HTTP URL。Deno 本身就支援它(它最初將整個模組系統都建立在 HTTP URL 上),但它在 Node 中僅透過自定義 HTTPS 載入器獲得實驗性支援。
-
file:URL 受許多非瀏覽器執行時(如 Node)支援,因為那裡的指令碼已經具有file:URL,但出於安全原因,瀏覽器不支援它們。 -
資料 URL 受包括瀏覽器、Node、Deno 等在內的許多執行時支援。它們對於將小型模組直接嵌入到原始碼中非常有用。支援的 MIME 型別是那些指定可匯入原始碼的型別,例如 JavaScript 的
text/javascript、JSON 模組的application/json、WebAssembly 模組的application/wasm等。(它們可能仍需要匯入屬性。)js// HTTP URLs import x from "https://example.com/x.js"; // Data URLs import x from "data:text/javascript,export default 42;"; // Data URLs for JSON modules import x from 'data:application/json,{"foo":42}' with { type: "json" };text/javascript資料 URL 仍被解釋為模組,但它們不能使用相對匯入——因為data:URL 方案不是分層的。也就是說,import x from "data:text/javascript,import y from './y.js';"將會丟擲錯誤,因為相對指定符'./y.js'無法解析。 -
node:URL 解析為內建的 Node.js 模組。它們受 Node 和其他聲稱與 Node 相容的執行時(如 Bun)支援。
裸指定符,由 CommonJS 推廣,在 node_modules 目錄中解析。例如,如果您有 import x from "foo",則執行時將在當前模組的父目錄中的任何 node_modules 目錄中查詢 foo 包。此行為可以透過使用匯入對映在瀏覽器中重現,匯入對映還允許您以其他方式自定義解析。
模組解析演算法也可以使用 HTML 規範定義的 import.meta.resolve 函式以程式設計方式執行。
示例
標準匯入
在此示例中,我們建立一個可重用模組,該模組匯出一個函式,用於獲取給定範圍內的所有素數。
// 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]
匯入的值只能由匯出者修改
被匯入的識別符號是即時繫結,因為匯出它的模組可以重新賦值它,並且匯入的值會改變。但是,匯入它的模組不能重新賦值它。儘管如此,任何持有匯出物件的模組都可以修改該物件,並且所有其他匯入相同值的模組都可以觀察到修改後的值。
您還可以透過模組名稱空間物件觀察新值。
// 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);
規範
| 規範 |
|---|
| ECMAScript® 2026 語言規範 # sec-imports |
瀏覽器相容性
載入中…
另見
exportimport()import.meta- 匯入斷言
- 在 blogs.windows.com 上預覽 ES6 模組以及 ES2015、ES2016 及更高版本(2016 年)
- hacks.mozilla.org 上的 ES6 深入:模組 (2015)
- hacks.mozilla.org 上的 ES 模組:卡通深度剖析 (2018)
- Axel Rauschmayer 博士的 探索 JS,第 16 章:模組
- 在 javascript.info 上匯出和匯入