JavaScript modules allow us to divide code into small pieces. They also let us keep some code private while exposing other pieces of code that can be imported into another module.
In this article, we’ll look at how to define and use modules.
Named exports start with the export
keyword – they expose items from inside a module to the outside. Then, we can import them somewhere else.
There can be multiple named exports in one module. For instance, we can write:
export const foo = 1; export let bar = 1;
Then, we can import them into another module as follows:
import { foo, bar } from "./module"; const baz = foo + bar;
We can also import the whole module with the *
sign as follows:
import * as module from "./module"; const baz = module.foo + module.bar;
import { foo, bar } from "./module";const baz = foo + bar;// pritingconsole.log(baz)
Try out the second method.
We can export one default export using the export default
keywords. For instance, we can write:
export default 1;
Then, import it as follows:
import foo from "./bar"; const baz = foo;
We can also export functions and class as follows:
export default () => {};
Or:
export default class {}
We don’t need a semicolon at the end of the class export. Also, we can define default exports with the following code:
const foo = 1; export { foo as default };
In browsers, scripts are denoted by the script
tag. Modules are the same, but it’s denoted by the type attribute with the value module
.
Scripts are not in strict mode by default, but modules are.
Top-level variables are global in scripts, but they are local to the module in modules.
The top-level value of this
is window
in scripts and undefined
in modules.
Scripts are run synchronously, while modules are run asynchronously.
There are no import
statements in scripts, but we can selectively import module members in modules.
We can programmatically import both scripts and modules using promise-based APIs.
An ES6 module can be statically analyzed for static checking, optimization, and more. It has a declarative syntax for importing and exporting.
Imports are hoisted to the top so that they can be referenced anywhere in the module.
For instance, if we have:
export const foo = 1;
Then, we can import it as follows:
import { foo } from "./bar"; const baz = foo;
Also, they must be at the top-level. Therefore, we can’t have something like this:
const baz = foo; import { foo } from "./bar";
ES6 imports are read-only views on export entities. Connections to variables inside the module that imported the export remain live.
For instance, if we have:
export const foo = 1;
Then, if we have the following:
import { foo } from "./bar"; foo = 1;
Then, we’ll get a read-only error. Let’s see this in the code snippet below:
import { foo } from "./bar";foo = 1;
We get the same result if we change the
const
tolet
.
If module A and B import members from each other, then we call it a cyclic dependency. This is supported with ES6 modules. For instance, if we have:
index.js
:
import { foo } from "./bar"; export const baz = 2;
bar.js
:
import { baz } from "./index"; export let foo = 1;
Then, the modules are cyclic dependencies since we can import a member from bar
in index
, and import a member from index
in bar
.
This works because imports just refer to the original data, so it doesn’t matter when they come from.
We can import JavaScript modules in various ways. One way is the default import, which is how we import members from a module.
For instance, we can write:
bar.js
:
let foo = 1; export default foo;
Then, we can import it as follows:
import foo from "./bar";
Named imports can be imported as follows (given the following named exports):
export let foo = 1;
Then, we can import it as follows:
import { foo } from "./bar";
We can rename named exports by using the as
keyword as follows:
import { foo as baz } from "./bar";
We can also rename default exports as follows:
import { default as foo } from "./bar";
We can also have empty where we don’t import anything. Instead, we run what’s included in the module.
For instance, if we have the following in bar.js
:
console.log("bar");
Then, we can run the code in bar.js
as follows:
import "./bar";
Therefore, we should see 'bar'
logged in the console log.
ES6 modules are a great way to divide code into small chunks. We can export module members and import them in another file. Imported members are read-only. Modules are in strict mode by default, which allows us to avoid a lot of the issues that come with non-strict mode.
Free Resources