JavaScript Module Import Export
JavaScript Module: Import und Export
Module ermöglichen saubere Code-Organisation und Wiederverwendbarkeit. Lernen Sie ES6 Module, verschiedene Export-Arten und Dynamic Imports.
Warum Module?
| Vorteil | Beschreibung |
|---|---|
| Kapselung | Private Variablen bleiben im Modul |
| Wiederverwendbarkeit | Code einmal schreiben, überall nutzen |
| Abhängigkeiten | Klare Imports statt globaler Variablen |
| Tree Shaking | Unbenutzter Code wird entfernt |
Named Exports
// math.js - Named Exports
// Einzeln exportieren
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// Oder am Ende gesammelt
const multiply = (a, b) => a * b;
const divide = (a, b) => a / b;
export { multiply, divide };
// Mit Umbenennung exportieren
const internalName = 'secret';
export { internalName as publicName };
// app.js - Named Imports
// Einzelne Imports
import { add, subtract } from './math.js';
console.log(add(2, 3)); // 5
console.log(subtract(5, 2)); // 3
// Mit Umbenennung importieren
import { add as addition } from './math.js';
console.log(addition(2, 3)); // 5
// Alle Imports als Namespace
import * as Math from './math.js';
console.log(Math.PI); // 3.14159
console.log(Math.multiply(3, 4)); // 12
Default Export
// user.js - Default Export
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hallo, ${this.name}!`;
}
}
// Nur EIN Default Export pro Modul!
export default User;
// Kann auch inline sein:
// export default class User { ... }
// app.js - Default Import
// Name beim Import ist frei wählbar!
import User from './user.js';
import MeinUser from './user.js'; // Gleicher Import
const user = new User('Max');
console.log(user.greet()); // "Hallo, Max!"
Kombinierte Exports
// api.js - Default + Named Exports kombiniert
// Default Export
export default class ApiClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async get(endpoint) {
const response = await fetch(`${this.baseUrl}${endpoint}`);
return response.json();
}
}
// Named Exports zusätzlich
export const API_VERSION = 'v1';
export function formatEndpoint(path) {
return path.startsWith('/') ? path : `/${path}`;
}
// app.js - Kombinierter Import
// Default und Named zusammen importieren
import ApiClient, { API_VERSION, formatEndpoint } from './api.js';
const api = new ApiClient('https://api.example.com');
console.log(API_VERSION); // "v1"
Re-Exports (Barrel Files)
// components/Button.js
export default function Button() { /* ... */ }
// components/Input.js
export default function Input() { /* ... */ }
// components/Modal.js
export default function Modal() { /* ... */ }
// components/index.js - Barrel File
// Re-export alles aus einem zentralen Punkt
export { default as Button } from './Button.js';
export { default as Input } from './Input.js';
export { default as Modal } from './Modal.js';
// Oder Named Exports weiterleiten
export * from './utils.js';
// app.js - Sauberer Import
// Statt vieler einzelner Imports:
// import Button from './components/Button.js';
// import Input from './components/Input.js';
// Ein Import für alle:
import { Button, Input, Modal } from './components/index.js';
// oder kurz:
import { Button, Input, Modal } from './components';
Dynamic Imports
// Statischer Import - wird sofort geladen
import { heavyFunction } from './heavy-module.js';
// Dynamischer Import - wird bei Bedarf geladen
async function loadHeavyModule() {
// import() gibt ein Promise zurück
const module = await import('./heavy-module.js');
// Named Exports
module.heavyFunction();
// Default Export
const DefaultClass = module.default;
}
// Praktisch für Code-Splitting
const button = document.getElementById('loadFeature');
button.addEventListener('click', async () => {
const { AdvancedFeature } = await import('./advanced-feature.js');
new AdvancedFeature().init();
});
// Bedingte Imports
const lang = navigator.language;
const translations = await import(`./locales/${lang}.js`);
Module im Browser
<!-- type="module" ist erforderlich -->
<script type="module" src="app.js"></script>
<!-- Inline Module -->
<script type="module">
import { greet } from './utils.js';
console.log(greet('Welt'));
</script>
<!-- Fallback für alte Browser -->
<script type="module" src="app.js"></script>
<script nomodule src="app-legacy.js"></script>
CommonJS vs ES Modules
// CommonJS (Node.js traditionell)
// --------------------------------
// Export
module.exports = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
// oder
exports.add = (a, b) => a + b;
// Import
const math = require('./math');
const { add, subtract } = require('./math');
// ES Modules (Modern)
// -------------------
// Export
export const add = (a, b) => a + b;
export default class Calculator {}
// Import
import Calculator, { add } from './math.js';
Wichtige Unterschiede
// ES Modules sind:
// - Statisch analysierbar (Tree Shaking möglich)
// - Asynchron geladen
// - Strict Mode standardmäßig
// - Top-level await möglich
// CommonJS ist:
// - Dynamisch (require kann überall stehen)
// - Synchron geladen
// - Kein automatischer Strict Mode
// In Node.js ES Modules nutzen:
// 1. Dateiendung .mjs verwenden
// 2. ODER "type": "module" in package.json
// package.json
{
"type": "module"
}
Zirkuläre Abhängigkeiten
// ⚠️ Vorsicht bei zirkulären Imports!
// a.js
import { b } from './b.js';
export const a = 'A';
console.log(b); // undefined beim ersten Durchlauf!
// b.js
import { a } from './a.js';
export const b = 'B';
console.log(a); // undefined beim ersten Durchlauf!
// Lösung: Abhängigkeiten umstrukturieren
// oder Funktionen statt Variablen exportieren
Best Practices
// ✅ Einen Default Export für Hauptfunktionalität
export default class UserService {}
// ✅ Named Exports für Utilities
export const validateEmail = (email) => { /* ... */ };
export const formatDate = (date) => { /* ... */ };
// ✅ Barrel Files für saubere Imports
// components/index.js
export * from './Button';
export * from './Input';
// ✅ Konsistente Namensgebung
// Dateiname = Export-Name
// Button.js → export default function Button()
// ❌ Vermeiden: Zu viele Re-Exports
// ❌ Vermeiden: Zirkuläre Abhängigkeiten
// ❌ Vermeiden: Side Effects im Modul-Scope
💡 Tipp:
Nutzen Sie Named Exports für Libraries mit mehreren Funktionen und Default Exports für Module mit einer Hauptfunktionalität. Dynamic Imports sind ideal für Code-Splitting und Lazy Loading.