How To Export Functions in JavaScript?

JavaScript modules allow encapsulating code into reusable files that can be imported into other scripts. However, by default, functions and variables declared in a module are not accessible from outside.

To make functions available to other modules, you need to explicitly export them. There are several syntax options for exporting in JavaScript:

  • Named exports to export individual objects
  • Default exports to export a single main object
  • Exporting from objects, classes, etc
  • Exporting aliases
  • Re-exporting to share between modules
  • Exporting constants, functions, classes, etc

In this guide, we’ll cover:

Exporting Basics

Named Exports

  • Exporting multiple named functions and variables
  • Import named exports using destructuring
  • Renaming named exports as

Default Exports

  • Exporting a single default function or object
  • Importing the default export
  • Limit of one default export per module

Exporting from Objects and Classes

  • Exporting specific members from objects
  • Exporting public class members
  • Encouraging encapsulation by design

Export Aliases

  • Creating alias names for exports using as
  • Avoiding naming conflicts
  • Readability with self-documenting aliases

Re-exporting Between Modules

  • Exporting symbols imported from another module
  • Re-exporting selectively
  • Aggregating and re-exporting grouped functionality

What Can Be Exported

  • Exporting functions, classes, variables, etc
  • Exporting constants with upper-case names
  • Exporting types like interfaces
  • Exporting React components

By the end, you’ll have a deep understanding of the various export options in JavaScript modules to share functions across your codebase. Let’s get started!

Exporting Basics

All exported symbols in a JavaScript module must be explicitly marked with the export keyword. There are two main categories of exports:

Named Exports

Named exports allow binding one or more objects to export:

// Named function exports
export function add(a, b) {
  return a + b;
}

export const pi = 3.14; 

// Equivalent shorthand

export {
  add,
  pi 
};
JavaScript

These exports must be imported using the same name.

Default Exports

Default exports provide a single main object export for a module:

// Default function export 

export default function(a, b) {
  return a + b;  
}

// Default class export
export default class Calculator {
  // ...
}
JavaScript

The default export can be imported using any name. Now let’s look at named exports in more detail.

Named Exports

Named exports provide fine-grained control over exporting specific symbols from a module.

For example:

// Export named function
export function add(a, b) {
  return a + b;
} 

// Export named constants
export const pi = 3.14;
export const e = 2.71;

// Export types
export interface Options {
  // ... 
}
JavaScript

You can export multiple named objects from a module this way.

Importing Named Exports with Destructuring

To import named exports, use destructured import:

import { add, pi, e } from './math.js';

console.log(pi) // 3.14
JavaScript

This allows importing only the named exports you need into the local scope.

Renaming Exports with as

Named exports can be aliased using as during import:

import { 
  add as sum, 
  pi as PI 
} from './math.js';

sum(1, 2); // 3
PI; // 3.14
JavaScript

This provides more readable identifiers when importing.

Next up – default exports!

Default Exports

Default exports provide an easy way to export a single main object from a module like a function or class.

Exporting a Default Function

To export a default function:

// math.js 

export default function sum(a, b) {
  return a + b;
}
JavaScript

Importing the Default Export

The default export can be imported using any name:

import add from './math.js';

add(1, 2); // 3
JavaScript

Unlike named exports, default exports do not need to be surrounded by brackets during import.

Limit of One Default Export

Each module can only have one default export. Additional exports must be named exports.

Default exports are useful for exporting “main” classes, functions, and values. Now let’s look at exporting from other constructs like objects and classes.

Exporting from Objects and Classes

So far we’ve seen standalone named and default exports. You can also export specific members of objects, classes, etc.

Exporting Members from Objects

To export specific properties from an object:

const math = {
  add, 
  sub,
  mul,

  pi: 3.14  
};

export {
  math.add,
  math.pi 
};
JavaScript

This exports add and pi but leaves other members private.

Exporting Public Class Members

Similarly, classes can export specific public members:

class Calculator {
  constructor() { ... }

  add(a, b) { ... }

  sub(a, b) { ... }
}

export {
  Calculator, // Export class 
  Calculator.add // Export class method
}
JavaScript

This provides granular control over the class API surface.

Encourages Encapsulation by Design

Exporting objects in this way naturally encourages encapsulation. Only exported members are exposed while others remain private.

Next let’s look at export aliases.

Export Aliases

Aliases can be useful when exporting to provide alternative named bindings for imports.

Creating Aliases with as

To specify an export alias:

function sum(a, b) {
  // ...
}

export {
  sum as add
};
JavaScript

Importers can now import { add } from './math.js' instead of sum.

Avoiding Naming Collisions

This allows for avoiding naming collisions when reusing conflicting names across modules.

For example:

// math.js
export {
  sum as add
}

// calc.js
export {
  add as sum  
}
JavaScript

Improving Readability

Aliases also help self-document the purpose of an export when the original symbol has a unclear name.

For example:

function normalize() { /* ... */ } 

export {
  normalize as normalizeInput  
};
JavaScript

The normalizeInput alias helps clarify what the function normalizes.

Next let’s see how to re-export symbols between modules.

Re-exporting Between Modules

Re-exporting provides a way to share exports between multiple modules.

Exporting Imported Symbols

To re-export a binding imported from another module:

// math.js
export function add(a, b) {
  return a + b;
}

// calc.js
import { add } from './math.js';

export { add } 
JavaScript

Now other modules can import add from calc.js instead of math.js directly.

Re-exporting Selectively

You can re-export selectively rather than everything:

// shapes.js
export * from './math.js'; // Re-export everything

export { add } from './math.js'; // Only re-export add
JavaScript

This allows the re-exporting of only the relevant parts.

Aggregating and Re-exporting

Re-exporting is useful for aggregating similar exports from multiple modules under a unified namespace:

// math.js
export function add() { /* ... */ }

// calc.js 
export function sub() { /* ... */ }

// operator.js
export * from './math.js';
export * from './calc.js'; // Export math and calc
JavaScript

This provides a cleaner API than each module separately.

Next, let’s look at what types of values can be exported.

What Can Be Exported

Many types of JavaScript declarations and values can be exported:

Functions

Exported functions form the core building blocks of reusable logic:

export function process(data) {
  // ...
}
JavaScript

Classes

Exported classes provide APIs and data structures to other code:

export class Parser {
  // ...
}
JavaScript

Variables

Simple values and stateless helpers can be exported as variables:

export const apiKey = 'xxx';
JavaScript

Constants

For constant values, use const and uppercase naming:

export const API_URL = 'https://api.example.com';
JavaScript

Interfaces and Types

Share TypeScript types using exported interfaces:

export interface Options {
  // ...
}
JavaScript

React Components

In React, components can be exported for use in other files:

export const Button = (props) => {
  // ... 
};
JavaScript

These are just some examples – you can export almost any value from a JavaScript module.

Summary

To summarize, exporting binds JS symbols to the module interface so they can be imported for reuse in other scripts:

  • Use named exports for multiple variable exports
  • Use a single default export for the main value
  • Export specific members from objects and classes
  • Use aliases to prevent naming collisions
  • Re-export values to share across modules
  • Functions, classes, data, types etc can all be exported

Exports enable writing encapsulated and modular JavaScript code. They encourage building reusable components that abstract complexity into self-contained units.

I hope this guide provides a solid overview of exporting functions in JavaScript modules. Let me know if you have any other questions!

Leave a Comment