Named Exports and Imports
The most common way to share code between modules is with named exports. You explicitly mark which values, functions, or classes a file makes available to other files.
Exporting a named value
Section titled “Exporting a named value”Add the export keyword before any declaration:
export class Expense { static CATEGORIES = ['Food', 'Transport', 'Health', 'Entertainment', 'Other'];
#id; #createdAt;
constructor({ id, description, amount, category, date, createdAt } = {}) { if (!description || description.trim() === '') throw new Error('Description is required'); if (typeof amount !== 'number' || amount <= 0) throw new Error('Amount must be positive');
this.#id = id ?? crypto.randomUUID(); this.#createdAt = createdAt ?? Date.now(); this.description = description.trim(); this.amount = amount; this.category = category ?? 'Other'; this.date = date ?? new Date().toISOString().split('T')[0]; }
get id() { return this.#id; } get createdAt() { return this.#createdAt; }
format() { return `${this.description}: $${this.amount.toFixed(2)}`; } isInCategory(c) { return this.category.toLowerCase() === c.toLowerCase(); } toJSON() { return { id: this.#id, description: this.description, amount: this.amount, category: this.category, date: this.date, createdAt: this.#createdAt }; }
static fromJSON(data) { return new Expense(data); } static isValidCategory(c) { return Expense.CATEGORIES.includes(c); }}You can export functions, classes, constants, and objects — any value:
export function saveExpenses(expenses) { localStorage.setItem('expenses', JSON.stringify(expenses.map(e => e.toJSON())));}
export function loadExpenses() { const raw = localStorage.getItem('expenses'); if (!raw) return []; return JSON.parse(raw).map(data => Expense.fromJSON(data));}Importing named exports
Section titled “Importing named exports”In the file that needs these values, use import { name } from './path':
import { Expense } from './expense.js';import { saveExpenses, loadExpenses } from './storage.js';
const expenses = loadExpenses();const coffee = new Expense({ description: 'Coffee', amount: 4.50, category: 'Food' });expenses.push(coffee);saveExpenses(expenses);Key rules:
- The imported name must exactly match the exported name (including case)
- The path must start with
./or../— not just the filename - Include the
.jsextension (required by native ES modules in the browser)
Exporting multiple names from one file
Section titled “Exporting multiple names from one file”A file can export as many names as it needs:
export function formatCurrency(amount) { return `$${amount.toFixed(2)}`;}
export function formatDate(dateString) { return new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', });}
export const DEFAULT_CURRENCY = 'USD';import { formatCurrency, formatDate, DEFAULT_CURRENCY } from './utils.js';Import only what you need — leaving out unused names does not cause errors.
Renaming on import
Section titled “Renaming on import”You can rename an import with as:
import { formatCurrency as fmt } from './utils.js';console.log(fmt(12.75)); // '$12.75'This is useful when two modules export names that would otherwise conflict.
Re-exporting
Section titled “Re-exporting”A module can import from one file and re-export for others to use. This is common in index files that collect and re-export everything from a folder:
export { Expense } from './expense.js';export { saveExpenses, loadExpenses } from './storage.js';export { formatCurrency, formatDate } from './utils.js';Now other files can import from ./index.js instead of knowing which specific file each name lives in.
Exercise
Section titled “Exercise”- Create
expense.jsand move yourExpenseclass into it with a named export. - Create
utils.jsand export two functions:formatCurrency(amount)andformatDate(dateString). - Create
main.jsthat importsExpensefrom./expense.jsand both utilities from./utils.js. - Create a few
Expenseinstances inmain.jsand logformatCurrency(expense.amount)for each. - Confirm the app works by opening
index.htmlin a local server.
exportbefore a declaration makes it available to other modules.import { name } from './file.js'brings a named export into the current file.- Names must match exactly; paths must start with
./or../and include.js. - Import only what you need — unused names are not imported.
- Rename with
asto avoid name collisions.