JavaScript export e import
Guida a export e import in JavaScript: export con nome, default export, rinomina con as, import dinamico, ri-esportazione ed errori comuni.
In JavaScript moderno, le parole chiave export e import consentono di suddividere un programma in più file e poi riunirli. Un file che le utilizza è un ES module: invece di inserire tutto in un unico script gigantesco, ogni funzionalità viene mantenuta nel proprio file, si dichiara cosa condivide con l'esterno (export) e si importa solo ciò che serve altrove (import).
Questa guida copre tutte le forme che incontrerai in pratica — export con nome, default export, rinomina con as, import di namespace, ri-esportazione e import() dinamico — e i trabocchetti più comuni. Ogni esempio è compatto ed eseguibile.
Perché usare i moduli?
Prima degli ES modules, condividere il codice significava attaccare elementi all'oggetto globale sperando che i nomi non collidessero. I moduli risolvono questo problema:
- Incapsulamento — tutto ciò che non esporti rimane privato al file.
- Dipendenze esplicite — le righe
importall'inizio di un file sono un elenco preciso di ciò su cui fa affidamento. - Valutazione unica — il codice di primo livello di un modulo viene eseguito una sola volta, indipendentemente da quanti file lo importano; il risultato viene memorizzato nella cache e condiviso.
Per eseguire i moduli nel browser, carica il tuo file di ingresso con type="module":
<script src="app.js" type="module"></script>In Node.js, rinomina i file con estensione .mjs oppure imposta "type": "module" in package.json.
Export con nome
Un export con nome esporta un'associazione con il proprio nome. Un modulo può avere quanti export con nome si desidera.
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
// You can also list exports at the bottom:
const subtract = (a, b) => a - b;
export { subtract };Gli export con nome si importano tra parentesi graffe, usando esattamente gli stessi nomi:
// app.js
import { add, PI } from './math.js';
console.log(add(2, 3)); // 5
console.log(PI); // 3.14159I nomi devono corrispondere all'export. import { Add } quando l'export è add genera un SyntaxError — non esiste un export con quel nome.
Rinomina con as
Quando due moduli esportano lo stesso nome, o un nome è scomodo, puoi rinominarlo all'ingresso (o all'uscita) usando as:
// Rename on import
import { add as sum } from './math.js';
console.log(sum(1, 1)); // 2// Rename on export
const internalAdd = (a, b) => a + b;
export { internalAdd as add };Default export
Un default export è l'unica cosa "principale" che un modulo fornisce. Un modulo può avere al massimo un default export.
// multiply.js
export default function multiply(a, b) {
return a * b;
}Quando si importa un default, non si usano le parentesi graffe e si sceglie il nome locale:
// app.js
import multiply from './multiply.js'; // any name works
console.log(multiply(4, 5)); // 20Poiché è l'importatore a scegliere il nome, i default export vengono spesso usati quando un file rappresenta una sola cosa — una singola classe, un singolo componente React, un singolo oggetto di configurazione.
Combinare default e export con nome
Un modulo può avere entrambi. Il default va fuori dalle parentesi graffe, quelli con nome dentro:
// user.js
export default class User { /* ... */ }
export const ADMIN_ROLE = 'admin';// app.js
import User, { ADMIN_ROLE } from './user.js';Preferisci gli export con nome per default. Rendono gli import auto-documentanti e consentono agli strumenti (completamento automatico, "trova riferimenti", tree-shaking) di funzionare in modo affidabile. Ricorri a un default export solo quando un file esporta davvero una cosa sola.
Tecniche di import
Import di namespace (import * as)
Per raccogliere tutto ciò che un modulo esporta in un singolo oggetto, usa un import di namespace:
// app.js
import * as math from './math.js';
console.log(math.add(5, 3)); // 8
console.log(math.PI); // 3.14159Ogni export con nome diventa una proprietà di math. Un default export, se presente, appare come math.default. Usa questa tecnica quando un modulo raggruppa molti helper correlati.
Import dinamico (import())
L'istruzione import vista sopra è statica — viene eseguita prima di qualsiasi altra cosa e il suo percorso deve essere una stringa letterale. A volte si vuole caricare un modulo su richiesta: solo quando l'utente apre una funzionalità, o in base a una condizione a runtime. Per questo si usa import() come funzione. Restituisce una Promise che si risolve con l'oggetto namespace del modulo:
// Load a heavy module only when needed
async function openEditor() {
const editor = await import('./editor.js');
editor.init();
}L'import dinamico funziona all'interno di funzioni e condizionali — posti dove un import statico non è consentito — il che lo rende la base del code-splitting e del lazy loading.
Ri-esportazione
Un file "barrel" può raccogliere gli export di più moduli e inoltrarli, in modo che i consumatori importino da un unico punto:
// shapes/index.js
export { Circle } from './circle.js';
export { Square } from './square.js';
export { default as Triangle } from './triangle.js'; // re-export a default as a name// app.js
import { Circle, Square, Triangle } from './shapes/index.js';Errori comuni
- Le estensioni contano nel browser e in Node ESM.
import { x } from './math'fallisce; scrivi'./math.js'. import/exportfunzionano solo al livello superiore di un modulo — non dentro un bloccoifo una funzione. Usaimport()dinamico per il caricamento condizionale.- Gli import sono associazioni live in sola lettura. Puoi leggere un valore importato ma non riassegnarlo;
add = 5su un import genera un errore. - Un default export non ha automaticamente un nome.
export default addesporta il valore, non il nomeadd; è l'importatore a scegliere il nome locale. - I moduli sono differiti ed eseguiti automaticamente in strict mode — non occorre
'use strict'.
Esempio pratico: un mini sistema bibliotecario
Qui diversi moduli esportano ciascuno un array di oggetti libro (objects), e un file principale li importa e li combina.
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Interactive Library App</title>
</head>
<body>
<h1>Interactive Library App</h1>
<button id="loadFiction">Load Fiction</button>
<button id="loadSciFi">Load Sci-Fi</button>
<div id="bookList"></div>
<script src="app.js" type="module"></script>
</body>
</html>fiction.js:
export const fictionBooks = [
{ title: 'Pride and Prejudice', author: 'Jane Austen' },
{ title: 'To Kill a Mockingbird', author: 'Harper Lee' }
];sciFi.js:
export const sciFiBooks = [
{ title: 'Dune', author: 'Frank Herbert' },
{ title: 'Neuromancer', author: 'William Gibson' }
];app.js:
import { fictionBooks } from './fiction.js';
import { sciFiBooks } from './sciFi.js';
function displayBooks(books) {
const list = document.getElementById('bookList');
list.innerHTML = '';
books.forEach(book => {
const item = document.createElement('div');
item.textContent = `${book.title} by ${book.author}`;
list.appendChild(item);
});
}
document
.getElementById('loadFiction')
.addEventListener('click', () => displayBooks(fictionBooks));
document
.getElementById('loadSciFi')
.addEventListener('click', () => displayBooks(sciFiBooks));Ogni categoria vive nel proprio modulo ed esporta una funzione o dei dati, e app.js li riunisce. Separare dati e comportamento in questo modo mantiene ogni file piccolo e rende banale aggiungere nuove categorie.
Buone pratiche
- Preferisci gli export con nome in modo che gli import si documentino da soli e il tree-shaking funzioni.
- Una responsabilità per modulo — un file dovrebbe essere facile da descrivere in una frase.
- Usa i file barrel con parsimonia — riordinano gli import ma possono penalizzare il tree-shaking se abusati.
- Carica in modo lazy il codice pesante o raramente usato con
import()dinamico. - Includi sempre le estensioni dei file nei percorsi relativi.
Conclusione
Gli export con nome ti danno più associazioni per file, il default export ti dà un'unica esportazione "principale", e import (con as, * as e import() dinamico) ti offre un controllo preciso su cosa entra e quando. Insieme trasformano un insieme di script in un grafo di moduli mantenibile e tree-shakeable. Scopri poi come i moduli vengono caricati nel browser in Modules, introduction.