W3docs

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 import all'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.14159
Informazione

I 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)); // 20

Poiché è 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';
Informazione

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.14159

Ogni 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/export funzionano solo al livello superiore di un modulo — non dentro un blocco if o una funzione. Usa import() dinamico per il caricamento condizionale.
  • Gli import sono associazioni live in sola lettura. Puoi leggere un valore importato ma non riassegnarlo; add = 5 su un import genera un errore.
  • Un default export non ha automaticamente un nome. export default add esporta il valore, non il nome add; è 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

  1. Preferisci gli export con nome in modo che gli import si documentino da soli e il tree-shaking funzioni.
  2. Una responsabilità per modulo — un file dovrebbe essere facile da descrivere in una frase.
  3. Usa i file barrel con parsimonia — riordinano gli import ma possono penalizzare il tree-shaking se abusati.
  4. Carica in modo lazy il codice pesante o raramente usato con import() dinamico.
  5. 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.

Esercitazione

Pratica
Quali affermazioni su export e import in JavaScript sono corrette?
Quali affermazioni su export e import in JavaScript sono corrette?
Was this page helpful?