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
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:
- Benannter Import:
import { export1, export2 } from "module-name";
- Standard-Import:
import defaultExport from "module-name";
- Namespace-Import:
import * as name from "module-name";
- Side Effekt Import:
import "module-name";
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.
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 Import umbenennen. Zum Beispiel wird so shortName
in den aktuellen Scope eingefügt.
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.
// /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"
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:
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:
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 den gleichen Effekt wie ein Standardimport. Es ist notwendig, den Namen als Alias zu verwenden, 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 Scope ein, das alle Exporte aus dem Modul bei /modules/my-module.js
enthält.
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:
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.
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.
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:
// 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 bereitsfile:
-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 dasdata:
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.
// 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 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.
// 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);
Spezifikationen
Specification |
---|
ECMAScript Language Specification # sec-imports |
Browser-Kompatibilität
BCD tables only load in the browser
Siehe auch
export
import()
import.meta
- Importattribute
- Previewing ES6 Modules und mehr von ES2015, ES2016 und darüber hinaus auf blogs.windows.com (2016)
- ES6 in Depth: Modules auf hacks.mozilla.org (2015)
- ES modules: A cartoon deep-dive auf hacks.mozilla.org (2018)
- Exploring JS, Kap.16: Module von Dr. Axel Rauschmayer
- Export und Import auf javascript.info