import
Baseline
Weitgehend verfügbar
*
Diese Funktion ist gut etabliert und funktioniert auf vielen Geräten und in vielen Browserversionen. Sie ist seit Mai 2018 browserübergreifend verfügbar.
* Einige Teile dieser Funktion werden möglicherweise unterschiedlich gut unterstützt.
Die statische import-Deklaration wird verwendet, um schreibgeschützte Live-Bindungen zu importieren, die von einem anderen Modul exportiert werden. Die importierten Bindungen werden als Live-Bindungen bezeichnet, weil sie durch das Modul aktualisiert werden, das die Bindung exportiert hat, aber nicht durch das importierende Modul neu zugewiesen werden können.
Um die import-Deklaration in einer Quelldatei verwenden zu können, muss die Datei von der Laufzeitumgebung als Modul interpretiert werden. In HTML wird dies durch Hinzufügen von type="module" zum <script>-Tag erreicht. Module werden automatisch im strikten Modus interpretiert.
Es gibt außerdem ein funktionsähnliches dynamisches import(), das keine Skripte vom Typ type="module" erfordert.
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-
Name, der sich auf den Standardexport des Moduls bezieht. Muss ein gültiger JavaScript-Identifier sein.
module-name-
Das Modul, aus dem importiert werden soll. Es sind nur Zeichenfolgenliterale mit einfachen oder doppelten Anführungszeichen zulässig. Die Auswertung des Spezifizierers wird durch den Host festgelegt. Die meisten Hosts orientieren sich an Browsern und lösen die Spezifizierer als URLs relativ zur URL des aktuellen Moduls auf (siehe
import.meta.url). Node, Bundler und andere Nicht-Browser-Umgebungen definieren häufig eigene Funktionen zusätzlich dazu. Daher sollten Sie deren Dokumentation konsultieren, um die genauen Regeln zu verstehen. Der Abschnitt Auflösung von Modulspezifizierern enthält ebenfalls weitere Informationen. name-
Name des Modulobjekts, das beim Verweisen auf die Importe als eine Art Namespace verwendet wird. Muss ein gültiger JavaScript-Identifier sein.
exportN-
Name der zu importierenden Exporte. Der Name kann entweder ein Identifier oder ein Zeichenfolgenliteral sein, abhängig davon, was
module-nameals Export deklariert. Wenn es sich um ein Zeichenfolgenliteral handelt, muss es mit einem Alias versehen werden, der ein gültiger Identifier ist. aliasN-
Namen, die sich auf die benannten Importe beziehen. Müssen gültige JavaScript-Identifier sein.
Auf "module-name" kann eine Reihe von Importattributen folgen, die mit dem Schlüsselwort with beginnen.
Beschreibung
import-Deklarationen dürfen nur in Modulen und nur auf der obersten Ebene vorhanden sein (d.h. nicht innerhalb von Blöcken, Funktionen usw.). Wenn eine import-Deklaration in Nicht-Modul-Kontexten angetroffen wird (beispielsweise in <script>-Tags ohne type="module", eval, new Function, die alle „script“ oder „function body“ als Parsing-Ziele haben), wird ein SyntaxError ausgelöst. Verwenden Sie stattdessen die Syntax für den dynamischen Import, um Module in Nicht-Modul-Kontexten zu laden.
Alle importierten Bindungen dürfen sich nicht im selben Gültigkeitsbereich wie irgendeine andere Deklaration befinden, einschließlich der Deklarationen let, const, class, function, var und import.
import-Deklarationen sind bewusst syntaktisch strikt gestaltet (beispielsweise nur Zeichenfolgenliteral-Spezifizierer, nur auf der obersten Ebene zulässig, alle Bindungen müssen Identifier sein). Dadurch können Module statisch analysiert und verknüpft werden, bevor sie ausgewertet werden. Dies ist der Schlüssel dazu, Module von Natur aus asynchron zu machen, und ermöglicht Funktionen wie top-level await.
Auf das Schlüsselwort import kann ein „Phasenmodifizierer“ folgen, der den Modulimportprozess in einer bestimmten Phase anhält:
Jede dieser Syntaxformen wird als eigener Deklarationstyp betrachtet.
Formen von import-Deklarationen
Es gibt vier Formen von import-Deklarationen:
- Benannter Import:
import { export1, export2 } from "module-name"; - Standardimport:
import defaultExport from "module-name"; - Namespace-Import:
import * as name from "module-name"; - Import nur für Seiteneffekte:
import "module-name";
Nachfolgend finden Sie Beispiele zur Verdeutlichung der Syntax.
Benannter Import
Angenommen, ein Wert namens myExport wurde aus dem Modul my-module exportiert, entweder implizit als export * from "another.js" oder explizit mithilfe der export-Anweisung. Dadurch wird myExport in den aktuellen Gültigkeitsbereich eingefügt.
import { myExport } from "/modules/my-module.js";
Sie können mehrere Namen aus demselben Modul importieren.
import { foo, bar } from "/modules/my-module.js";
Sie können einen Export beim Importieren umbenennen. Beispielsweise wird dadurch shortName in den aktuellen Gültigkeitsbereich eingefügt.
import { reallyReallyLongModuleExportName as shortName } from "/modules/my-module.js";
Ein Modul kann ein Mitglied auch als Zeichenfolgenliteral exportieren, das kein gültiger Identifier ist. In diesem Fall müssen Sie ihm einen Alias geben, um es im aktuellen Modul verwenden zu können.
// /modules/my-module.js
const a = 1;
export { a as "a-b" };
import { "a-b" as a } from "/modules/my-module.js";
Hinweis:
import { x, y } from "mod" entspricht nicht import defaultExport from "mod" mit anschließendem Destrukturieren von x und y aus defaultExport. Benannte und Standardimporte sind in JavaScript-Modulen unterschiedliche Syntaxformen.
Standardimport
Standardexporte müssen mit der entsprechenden Syntax für Standardimporte importiert werden. Diese Variante importiert den Standardexport direkt:
import myDefault from "/modules/my-module.js";
Da der Standardexport nicht explizit einen Namen angibt, können Sie dem Identifier einen beliebigen Namen geben.
Es ist auch möglich, einen Standardimport zusammen mit Namespace-Importen oder benannten Importen anzugeben. In solchen Fällen muss der Standardimport zuerst deklariert werden. Zum Beispiel:
import myDefault, * as myModule from "/modules/my-module.js";
// myModule.default and myDefault point to the same binding
oder
import myDefault, { foo, bar } from "/modules/my-module.js";
Das Importieren eines Namens namens default hat denselben Effekt wie ein Standardimport. Der Name muss mit einem Alias versehen werden, da default ein reserviertes Wort ist.
import { default as myDefault } from "/modules/my-module.js";
Namespace-Import
Der folgende Code fügt myModule in den aktuellen Gültigkeitsbereich ein und enthält alle Exporte aus dem Modul unter /modules/my-module.js.
import * as myModule from "/modules/my-module.js";
Hier stellt myModule ein Namespace-Objekt dar, das alle Exporte als Eigenschaften enthält. Wenn das oben importierte Modul beispielsweise einen Export doAllTheAmazingThings() enthält, würden Sie ihn wie folgt aufrufen:
myModule.doAllTheAmazingThings();
myModule ist ein versiegeltes Objekt mit null-Prototyp. Der Standardexport ist als Schlüssel namens default verfügbar. Weitere Informationen finden Sie unter Modul-Namespace-Objekt.
Hinweis:
JavaScript unterstützt keine Wildcard-Importe wie import * from "module-name", da ein hohes Potenzial für Namenskonflikte besteht.
Ein Modul nur für seine Seiteneffekte importieren
Importieren Sie ein vollständiges Modul nur für Seiteneffekte, ohne etwas zu importieren. Dadurch wird der globale Code des Moduls ausgeführt, aber es werden tatsächlich keine Werte importiert.
import "/modules/my-module.js";
Dies wird häufig für Polyfills verwendet, die globale Variablen verändern.
Hoisting
Importdeklarationen werden gehoistet. In diesem Fall bedeutet das, dass die von den Importen eingeführten Identifier im gesamten Modul-Gültigkeitsbereich verfügbar sind und ihre Seiteneffekte erzeugt werden, bevor der übrige Code des Moduls ausgeführt wird.
myModule.doAllTheAmazingThings(); // myModule.doAllTheAmazingThings is imported by the next line
import * as myModule from "/modules/my-module.js";
Auflösung von Modulspezifizierern
Die ECMAScript-Spezifikation definiert nicht, wie Modulspezifizierer aufgelöst werden, und überlässt dies der Hostumgebung (z. B. Browsern, Node.js, Deno). Das Verhalten von Browsern wird durch die HTML-Spezifikation festgelegt und ist zur de facto-Grundlage für alle Umgebungen geworden.
Es gibt drei weithin anerkannte Arten von Spezifizierern, wie sie von der HTML-Spezifikation, Node und vielen anderen implementiert werden:
- Relative Spezifizierer, die mit
/,./oder../beginnen und relativ zur URL des aktuellen Moduls aufgelöst werden. - Absolute Spezifizierer, die analysierbare URLs sind und unverändert aufgelöst werden.
- Bare-Spezifizierer, die keiner der oben genannten Arten entsprechen.
Die bemerkenswerteste Einschränkung bei relativen Spezifizierern, insbesondere für Personen, die mit den CommonJS-Konventionen vertraut sind, besteht darin, dass Browser nicht zulassen, dass ein Spezifizierer implizit zu vielen potenziellen Kandidaten aufgelöst wird. Wenn Sie in CommonJS main.js und utils/index.js haben, importieren alle folgenden Varianten den „Standardexport“ aus 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
Im Web ist dies kostspielig, denn wenn Sie import x from "./utils" schreiben, muss der Browser Anfragen an utils, utils/index.js, utils.js und möglicherweise viele weitere URLs senden, bis er ein importierbares Modul findet. Daher kann der Spezifizierer in der HTML-Spezifikation standardmäßig nur eine URL sein, die relativ zur URL des aktuellen Moduls aufgelöst wird. Sie können die Dateierweiterung oder den Dateinamen index.js nicht weglassen. Dieses Verhalten wurde von der ESM-Implementierung von Node übernommen, ist jedoch nicht Teil der ECMAScript-Spezifikation.
Beachten Sie, dass dies nicht bedeutet, dass import x from "./utils" im Web niemals funktioniert. Der Browser sendet weiterhin eine Anfrage an diese URL, und wenn der Server mit dem richtigen Inhalt antworten kann, ist der Import erfolgreich. Dies erfordert, dass der Server eine benutzerdefinierte Auflösungslogik implementiert, da Anfragen ohne Erweiterung normalerweise als Anfragen nach HTML-Dateien verstanden werden.
Absolute Spezifizierer können jede Art von URL sein, die zu importierbarem Quellcode aufgelöst wird. Besonders hervorzuheben sind:
-
HTTP-URLs werden im Web immer unterstützt, da die meisten Skripte bereits HTTP-URLs haben. Deno unterstützt sie nativ, da sein gesamtes Modulsystem ursprünglich auf HTTP-URLs basiert, während Node sie nur experimentell über benutzerdefinierte HTTPS-Loader unterstützt.
-
file:-URLs werden von vielen Nicht-Browser-Laufzeitumgebungen wie Node unterstützt, da Skripte dort bereitsfile:-URLs haben. Aus Sicherheitsgründen werden sie jedoch nicht von Browsern unterstützt. -
Data-URLs werden von vielen Laufzeitumgebungen unterstützt, einschließlich Browsern, Node, Deno usw. Sie sind nützlich, um kleine Module direkt in den Quellcode einzubetten. Unterstützte MIME-Typen sind solche, die importierbaren Quellcode bezeichnen, beispielsweise
text/javascriptfür JavaScript,application/jsonfür JSON-Module,application/wasmfür WebAssembly-Module usw. (Sie können dennoch Importattribute erfordern.)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-Data-URLs werden weiterhin als Module interpretiert, können jedoch keine relativen Importe verwenden — da das URL-Schemadata:nicht hierarchisch ist. Das heißt,import x from "data:text/javascript,import y from './y.js';"löst einen Fehler aus, weil der relative Spezifizierer'./y.js'nicht aufgelöst werden kann. -
node:-URLs werden zu integrierten Node.js-Modulen aufgelöst. Sie werden von Node und anderen Laufzeitumgebungen unterstützt, die Kompatibilität mit Node beanspruchen, wie beispielsweise Bun.
Bare-Spezifizierer, die durch CommonJS populär wurden, werden innerhalb des Verzeichnisses node_modules aufgelöst. Wenn Sie beispielsweise import x from "foo" haben, sucht die Laufzeitumgebung nach dem Paket foo in jedem Verzeichnis node_modules in den übergeordneten Verzeichnissen des aktuellen Moduls. Dieses Verhalten kann in Browsern mithilfe von Import Maps nachgebildet werden, die Ihnen außerdem ermöglichen, die Auflösung auf andere Weise anzupassen.
Der Modուլauflösungsalgorithmus kann auch programmgesteuert über die durch die HTML-Spezifikation definierte Funktion import.meta.resolve ausgeführt werden.
Beispiele
>Standardimport
In diesem Beispiel erstellen wir ein wiederverwendbares Modul, das eine Funktion exportiert, um alle Primzahlen innerhalb eines bestimmten Bereichs abzurufen.
// 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]
Importierte Werte können nur durch den Exporteur verändert werden
Der importierte Identifier ist eine Live-Bindung, weil das Modul, das ihn exportiert, ihn neu zuweisen kann und sich der importierte Wert dadurch ändert. Das Modul, das ihn importiert, kann ihn jedoch nicht neu zuweisen. Dennoch kann jedes Modul, das ein exportiertes Objekt hält, das Objekt verändern, und der veränderte Wert kann von allen anderen Modulen beobachtet werden, die denselben Wert importieren.
Sie können den neuen Wert auch über das Modul-Namespace-Objekt beobachten.
// 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);
Importieren von Nicht-JavaScript-Modulen
Nicht-JavaScript-Module können ebenfalls mit der import-Anweisung importiert werden, ihre Typen müssen jedoch explizit mithilfe von Importattributen deklariert werden. Um beispielsweise ein JSON-Modul zu importieren, müssen Sie das Attribut type: "json" angeben.
import data from "./data.json" with { type: "json" };
Spezifikationen
| Spezifikation |
|---|
| ECMAScript® 2027 Language Specification> # sec-imports> |
Browser-Kompatibilität
Siehe auch
exportimport()import.meta- Importattribute
- Vorschau auf ES6-Module und mehr aus ES2015, ES2016 und darüber hinaus auf blogs.windows.com (2016)
- ES6 im Detail: Module auf hacks.mozilla.org (2015)
- ES-Module: Ein Cartoon-Tiefenblick auf hacks.mozilla.org (2018)
- Exploring JS, Kap. 16: Module von Dr. Axel Rauschmayer
- Export und Import auf javascript.info