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.

Die statische import Erklärung wird verwendet, um schreibgeschützte Live-Bindings zu importieren, die von einem anderen Modul exportiert werden. Die importierten Bindings werden als Live-Bindings bezeichnet, weil sie von dem Modul, das das Binding exportiert hat, aktualisiert werden, jedoch nicht vom importierenden Modul neu zugewiesen werden können.

Um die import-Erklärung in einer Quelldatei zu verwenden, 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 Strict Mode interpretiert.

Es gibt auch eine funktionsähnliche dynamische import(), die keine Skripte vom Typ type="module" erfordert.

Syntax

js
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 Standard-Export des Moduls bezieht. Muss ein gültiger JavaScript-Identifikator sein.

module-name

Das Modul, aus dem importiert werden soll. Es sind nur einzelne und doppelt zitierte Zeichenfolgenliterale erlaubt. Die Bewertung des Specifiers ist host-spezifiziert. Die meisten Hosts orientieren sich an Browsern und lösen die Specifier als URLs relativ zur aktuellen Modul-URL auf (siehe import.meta.url). Node, Bundler und andere Nicht-Browser-Umgebungen definieren oft ihre eigenen Funktionen darüber hinaus, deshalb sollten Sie die Dokumentation dafür finden, um die genauen Regeln zu verstehen. Die Modul-Spezifier-Resolution Sektion hat ebenfalls weitere Informationen.

name

Name des Modulobjekts, das als eine Art Namespace verwendet wird, wenn auf die Importe verwiesen wird. Muss ein gültiger JavaScript-Identifikator sein.

exportN

Namen der zu importierenden Exporte. Der Name kann entweder ein Identifikator oder ein Stringliterale sein, abhängig davon, was module-name exportieren deklariert. Wenn es sich um ein Stringliteral handelt, muss es als gültiger Identifikator aliasisiert werden.

aliasN

Namen, die auf die benannten Importe verweisen. Muss ein gültiger JavaScript-Identifikator sein.

Der "module-name" kann von einer Reihe von Importattributen gefolgt werden, beginnend mit dem with Schlüsselwort.

Beschreibung

Import-Erklärungen können nur in Modulen und nur auf oberster Ebene (d.h. nicht innerhalb von Blöcken, Funktionen usw.) vorhanden sein. Wenn eine import-Erklärung in Nicht-Modul-Kontexten (zum Beispiel <script> Tags ohne type="module", eval, new Function, die alle "script" oder "function body" als Parsing-Ziele haben) auftaucht, wird ein SyntaxError erzeugt. Um Module in Nicht-Modul-Kontexten zu laden, verwenden Sie stattdessen die dynamische Import Syntax.

Alle importierten Bindings dürfen nicht im gleichen Scope wie jede andere Deklaration sein, einschließlich let, const, class, function, var, und import Deklaration.

Import-Erklärungen sind so gestaltet, syntaktisch strikt zu sein (zum Beispiel nur stringliterale Specifier, nur auf oberster Ebene zugelassen, alle Bindings müssen Identifikatoren sein), was es ermöglicht, Module statisch zu analysieren und zu verlinken, bevor sie ausgewertet werden. Dies ist der Schlüssel, um Module von Natur aus asynchron zu machen und Funktionen wie Top-Level await zu betreiben.

Formen von Import-Erklärungen

Es gibt vier Formen von import-Erklärungen:

Nachfolgend sind Beispiele, um die Syntax zu verdeutlichen.

Benannter Import

Bei einem Wert namens myExport, der aus dem Modul my-module entweder implizit als export * from "another.js" oder explizit mit der export Anweisung exportiert wurde, wird myExport in den aktuellen Scope eingefügt.

js
import { myExport } from "/modules/my-module.js";

Sie können mehrere Namen aus demselben Modul importieren.

js
import { foo, bar } from "/modules/my-module.js";

Sie können einen Export beim Import umbenennen. Zum Beispiel wird so shortName in den aktuellen Scope eingefügt.

js
import { reallyReallyLongModuleExportName as shortName } from "/modules/my-module.js";

Ein Modul kann auch ein Mitglied als Stringliteral exportieren, welches kein gültiger Identifikator ist, in diesem Fall müssen Sie es als Alias verwenden, um es im aktuellen Modul zu nutzen.

js
// /modules/my-module.js
const a = 1;
export { a as "a-b" };
js
import { "a-b" as a } from "/modules/my-module.js";

Hinweis: import { x, y } from "mod" ist nicht gleichbedeutend mit import defaultExport from "mod" und dann Destrukturierung von x und y von defaultExport. Benannte und Standardimporte sind unterschiedliche Syntaxe in JavaScript-Modulen.

Standard-Import

Standard-Exporte müssen mit der entsprechenden Standard-Import-Syntax importiert werden. Diese Version importiert direkt den Standard:

js
import myDefault from "/modules/my-module.js";

Da der Standardexport keinen Namen ausdrücklich angibt, können Sie dem Identifikator einen beliebigen Namen geben, den Sie möchten.

Es ist auch möglich, einen Standardimport mit Namespace-Importen oder benannten Importen zu spezifizieren. In solchen Fällen muss der Standardimport zuerst deklariert werden. Zum Beispiel:

js
import myDefault, * as myModule from "/modules/my-module.js";
// myModule.default and myDefault point to the same binding

oder

js
import myDefault, { foo, bar } from "/modules/my-module.js";

Das Importieren eines Namens namens default hat den gleichen Effekt wie ein Standardimport. Es ist notwendig, den Namen als Alias zu verwenden, da default ein reserviertes Wort ist.

js
import { default as myDefault } from "/modules/my-module.js";

Namespace-Import

Der folgende Code fügt myModule in den aktuellen Scope ein, das alle Exporte aus dem Modul bei /modules/my-module.js enthält.

js
import * as myModule from "/modules/my-module.js";

Hierbei stellt myModule ein Namespace-Objekt dar, das alle Exporte als Eigenschaften enthält. Zum Beispiel, wenn das oben importierte Modul einen Export doAllTheAmazingThings() beinhaltet, würden Sie es so aufrufen:

js
myModule.doAllTheAmazingThings();

MyModule ist ein versiegeltes Objekt mit null Prototyp. Der Standardexport ist als ein Schlüssel namens default verfügbar. Für weitere Informationen siehe Modul-Namespace-Objekt.

Hinweis: JavaScript hat keine Wildcard-Importe wie import * from "module-name", wegen der hohen Möglichkeit von Namenskonflikten.

Import eines Moduls nur für seine Seiteneffekte

Importieren Sie ein gesamtes Modul nur für Seiteneffekte, ohne irgendetwas zu importieren. Dies führt den globalen Code des Moduls aus, importiert jedoch keine Werte tatsächlich.

js
import "/modules/my-module.js";

Dies wird häufig für Polyfills verwendet, die die globalen Variablen verändern.

Hoisting

Import-Erklärungen sind gehoist. In diesem Fall bedeutet das, dass die Identifikatoren, die die Importe einführen, im gesamten Moduluşcope verfügbar sind und ihre Seiteneffekte vor dem Rest des Modulkodes produziert werden.

js
myModule.doAllTheAmazingThings(); // myModule.doAllTheAmazingThings is imported by the next line

import * as myModule from "/modules/my-module.js";

Modul-Spezifier-Resolution

Die ECMAScript-Spezifikation definiert nicht, wie Modul-Spezifier aufgelöst werden und überlässt dies der Host-Umgebung (z.B. Browser, Node.js, Deno). Das Verhalten der Browser wird von der HTML-Spezifikation spezifiziert, und dies wurde zum de facto Standard für alle Umgebungen.

Es gibt drei Typen von Spezifiern, die weit anerkannt sind, wie sie von der HTML-Spezifikation, Node und vielen anderen implementiert werden:

  • Relative Specifier, die mit /, ./ oder ../ beginnen, welche relativ zur aktuellen Modul-URL aufgelöst werden.
  • Absolute Specifier, die parsebare URLs sind, die so wie sie sind aufgelöst werden.
  • Bare Specifier, die nicht zu den obigen gehören.

Die bemerkenswerteste Einschränkung für relative Specifier, besonders für Personen, die mit den CommonJS Konventionen vertraut sind, ist, dass Browser verbieten, dass ein Specifier implizit zu vielen potenziellen Kandidaten aufgelöst wird. In CommonJS, wenn Sie main.js und utils/index.js haben, dann werden alle folgenden den "Standardexport" von utils/index.js importieren:

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 das kostspielig, weil, wenn Sie import x from "./utils" schreiben, der Browser Anfragen an utils, utils/index.js, utils.js und möglicherweise viele andere URLs senden muss, bis es ein importierbares Modul findet. Daher kann in der HTML-Spezifikation der Specifier standardmäßig nur eine URL sein, die relativ zur aktuellen Modul-URL aufgelöst wird. Sie können die Dateiendung oder den index.js Dateinamen nicht weglassen. Dieses Verhalten wurde von Node's ESM-Implementierung übernommen, ist jedoch kein Teil der ECMAScript-Spezifikation.

Beachten Sie, dass dies nicht bedeutet, dass import x from "./utils" nie im Web funktioniert. Der Browser sendet immer noch eine Anfrage an diese URL, und wenn der Server mit dem korrekten Inhalt antworten kann, wird der Import erfolgreich sein. Dies erfordert, dass der Server einige benutzerdefinierte Auflösungslogik implementiert, da normalerweise verlustfreie Anfragen als Anfragen für HTML-Dateien verstanden werden.

Absolute Specifier können jede Art von URL sein, die zu importierbarem Quellcode aufgelöst wird. Am bemerkenswertesten:

  • HTTP-URLs werden immer im Web unterstützt, da die meisten Skripte bereits HTTP-URLs haben. Es wird nativ von Deno unterstützt (das zuerst sein gesamtes Modulsystem auf HTTP-URLs aufgesetzt hat), aber es hat nur experimentelle Unterstützung in Node über benutzerdefinierte HTTPS-Loader.

  • File:-URLs werden von vielen Nicht-Browser-Laufzeiten wie Node unterstützt, da Skripte dort bereits file:-URLs haben, aber sie werden aus Sicherheitsgründen nicht von Browsern unterstützt.

  • Daten-URLs werden von vielen Laufzeiten einschließlich Browsern, Node, Deno, etc. unterstützt. Sie sind nützlich, um kleine Module direkt in den Quellcode einzubetten. Unterstützte MIME-Typen sind diejenigen, die importierbaren Quellcode bezeichnen, wie text/javascript für JavaScript, application/json für JSON-Module, application/wasm für WebAssembly-Module, etc. (Sie können trotzdem 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 Daten-URLs werden immer noch als Module interpretiert, aber sie können keine relativen Importe verwenden — da das data: URL-Schema nicht hierarchisch ist. Das heißt, import x from "data:text/javascript,import y from './y.js';" wird einen Fehler werfen, weil der relative Specifier './y.js' nicht aufgelöst werden kann.

  • Node:-URLs werden auf eingebaute Node.js-Module aufgelöst. Sie werden von Node und anderen Laufzeiten unterstützt, die Kompatibilität mit Node beanspruchen, wie Bun.

Bare Specifier, popularisiert von CommonJS, werden innerhalb des node_modules Verzeichnisses aufgelöst. Wenn Sie zum Beispiel import x from "foo" haben, dann wird die Laufzeit nach dem foo Paket innerhalb eines node_modules Verzeichnisses in den Elternverzeichnissen des aktuellen Moduls suchen. Dieses Verhalten kann in Browsern mit Importmaps reproduziert werden, die es Ihnen auch ermöglichen, die Auflösung auf andere Weise anzupassen.

Der Modulspezifizierungsalgorithmus kann auch programmgesteuert mit der von der HTML-Spezifikation definierten import.meta.resolve Funktion ausgeführt werden.

Beispiele

Standardimport

In diesem Beispiel erstellen wir ein wiederverwendbares Modul, das eine Funktion exportiert, um alle Primzahlen innerhalb eines gegebenen Bereichs zu erhalten.

js
// 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);
}
js
import { getPrimes } from "/modules/getPrimes.js";

console.log(getPrimes(10)); // [2, 3, 5, 7]

Importierte Werte können nur vom Exporteur geändert werden

Der identifizierte Wert, der importiert wird, ist ein Live-Binding, weil das Modul, das es exportiert, es neu zuweisen kann und der importierte Wert sich ändern würde. Allerdings kann das Modul, das es importiert, es nicht neu zuweisen. Trotzdem 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 durch das Modul-Namespace-Objekt beobachten.

js
// my-module.js
export let myValue = 1;
setTimeout(() => {
  myValue = 2;
}, 500);
js
// 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);

Spezifikationen

Specification
ECMAScript Language Specification
# sec-imports

Browser-Kompatibilität

BCD tables only load in the browser

Siehe auch