JavaScript tutorials > Object-Oriented JavaScript > Encapsulation and Modules > How do you use export and import in JavaScript?

How do you use export and import in JavaScript?

This tutorial explains how to use export and import in JavaScript to create modular and reusable code. We'll cover different types of exports, importing specific members, aliasing, and best practices for organizing your JavaScript projects.

Introduction to ES Modules

Before ES Modules, JavaScript relied on script tags and other module systems like CommonJS (used in Node.js) or AMD. ES Modules, introduced in ES6 (ECMAScript 2015), provide a standardized way to organize and share JavaScript code. They offer better performance, reusability, and maintainability compared to traditional methods.

Named Exports

Named exports allow you to export multiple functions, variables, or classes from a module. Each export has a name, and you can import these names individually. In the math_functions.js file, we export two functions, add and subtract. In app.js, we import only the functions we need, explicitly specifying them within curly braces.

/* math_functions.js */
export function add(x, y) {
  return x + y;
}

export function subtract(x, y) {
  return x - y;
}

/* app.js */
import { add, subtract } from './math_functions.js';

console.log(add(5, 3)); // Output: 8
console.log(subtract(5, 3)); // Output: 2

Default Exports

Default exports allow you to export a single value from a module. This could be a function, a class, an object, or any other JavaScript value. Unlike named exports, you don't use curly braces when importing a default export, and you can choose any name you like for the imported variable. In the my_module.js file, we export myVariable as the default export. In app.js, we import it as myVar.

/* my_module.js */
const myVariable = 42;

export default myVariable;

/* app.js */
import myVar from './my_module.js';

console.log(myVar); // Output: 42

Combining Named and Default Exports

You can combine both named and default exports within a single module. This is useful when you have a primary value to export (default) along with additional utilities or constants (named exports). In utils.js, we export PI as the default export and formatDate as a named export. In app.js, we import both, using the correct syntax for each type of export.

/* utils.js */
export function formatDate(date) {
  return date.toLocaleDateString();
}

const PI = 3.14159;
export default PI;

/* app.js */
import PI, { formatDate } from './utils.js';

console.log(PI); // Output: 3.14159
console.log(formatDate(new Date())); // Output: (current date in local format)

Importing All Named Exports with *

You can import all named exports from a module into a single object using the * as syntax. This is useful when you want to access multiple named exports without explicitly listing them all. In helpers.js, we have two named exports: capitalize and reverseString. In app.js, we import all of them into the helpers object. We can then access each function using dot notation (e.g., helpers.capitalize).

/* helpers.js */
export function capitalize(str) {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

export function reverseString(str) {
  return str.split('').reverse().join('');
}

/* app.js */
import * as helpers from './helpers.js';

console.log(helpers.capitalize('hello')); // Output: Hello
console.log(helpers.reverseString('world')); // Output: dlrow

Aliasing Exports and Imports

You can rename exports and imports using the as keyword. This is helpful when you want to avoid naming conflicts or use more descriptive names in your current module. In api.js, we export getData as fetchData. In app.js, we import fetchData as getApiData.

/* api.js */
function getData() {
  // ... fetch data from API ...
  return 'Data from API';
}

export { getData as fetchData };

/* app.js */
import { fetchData as getApiData } from './api.js';

console.log(getApiData()); // Output: Data from API

Dynamic Imports

Dynamic imports allow you to load modules asynchronously, on demand. This can improve performance by only loading the code that's needed when it's needed. Dynamic imports return a promise that resolves to the module's exports. Dynamic imports are especially useful for lazy-loading modules or loading modules based on user interactions or conditions. This is the only way to import modules in non-module environments.

async function loadModule() {
  const module = await import('./my_dynamic_module.js');
  module.myFunction();
}

loadModule();

concepts behind the snippet

The key concepts behind export and import are:

  • Modularity: Breaking down your code into smaller, reusable modules.
  • Reusability: Using the same code in multiple places without duplication.
  • Maintainability: Making your code easier to understand, debug, and update.
  • Namespace management: Avoiding naming conflicts by encapsulating code within modules.
  • Dependency management: Clearly defining the dependencies between modules.

Real-Life Use Case Section

Consider a large web application with numerous features. Using export and import can help organize the codebase into separate modules for each feature (e.g., user authentication, product catalog, shopping cart). Each module can export its specific functions, classes, or components, which can then be imported and used by other modules as needed. This makes the application easier to develop, test, and maintain.

Best Practices

  • Be explicit with your exports and imports: Avoid importing unnecessary code, as it can increase your bundle size.
  • Use descriptive names: Choose clear and concise names for your exports and imports to improve code readability.
  • Organize your modules logically: Group related code into separate modules based on functionality or feature.
  • Use a module bundler: Tools like Webpack, Parcel, or Rollup can help you bundle your modules into optimized files for production.
  • Favor named exports over default exports when possible: Named exports generally provide better discoverability and refactoring support.

Interview Tip

When discussing export and import in an interview, be sure to demonstrate your understanding of the different types of exports, how to import them, and the benefits of using ES modules for code organization and maintainability. Explain the difference between named and default exports, and when to use each one. Also, be prepared to discuss module bundlers and their role in optimizing JavaScript code for production.

When to use them

Use export and import in JavaScript when you want to:

  • Break down your code into smaller, manageable modules.
  • Share code between different parts of your application.
  • Reuse code in multiple projects.
  • Improve code organization and maintainability.
  • Reduce the risk of naming conflicts.

Memory footprint

ES modules can help reduce the memory footprint of your application by only loading the code that's needed. Module bundlers can also perform tree shaking, which eliminates unused code from your bundle. Dynamic imports can further reduce the initial load time and memory usage by loading modules on demand.

alternatives

Alternatives to ES Modules (though generally not recommended for modern projects) include:

  • CommonJS: Used primarily in Node.js.
  • AMD (Asynchronous Module Definition): Used primarily in browsers for asynchronous module loading.
  • Global variables: Assigning values to the window object (not recommended due to potential naming conflicts and lack of encapsulation).

pros

  • Improved code organization: ES modules enforce a clear structure for your codebase.
  • Enhanced reusability: Modules can be easily reused across different parts of your application or in other projects.
  • Better maintainability: Modular code is easier to understand, debug, and update.
  • Reduced risk of naming conflicts: Modules provide a separate namespace for your code.
  • Performance optimization: Module bundlers can optimize your code for production by tree shaking and other techniques.

cons

  • Requires a build process: ES modules typically require a module bundler to be used in browsers (though modern browsers are increasingly supporting native ES modules).
  • Can increase complexity: Introducing modules can add complexity to smaller projects.
  • Learning curve: Understanding the different types of exports and imports can take some time to learn.

FAQ

  • What is the difference between named and default exports?

    Named exports allow you to export multiple values from a module, each with a specific name. You import these values by their names, enclosed in curly braces. Default exports allow you to export a single value from a module. You import this value without curly braces and can choose any name for the imported variable.

  • Do I need a module bundler to use export and import?

    While modern browsers are increasingly supporting native ES modules, a module bundler like Webpack, Parcel, or Rollup is still recommended for most projects. Bundlers provide features like tree shaking, code minification, and polyfills, which can significantly improve performance and compatibility. Without a bundler, you might face challenges with older browsers or complex dependency graphs.

  • Can I use export and import in Node.js?

    Yes, you can use export and import in Node.js, but you'll need to configure your project to use ES modules. This typically involves setting the "type": "module" property in your package.json file or using the .mjs file extension for your JavaScript files.