Lesson notes

You can divide your code into separate modules. In JavaScript there is one module per file.

Connecting code located in different modules consists of two parts:

  1. Export something from a module.
  2. Import it into another module.

Export and two ways of importing

Put export in front of anything you want to export. This will make it importable elsewhere:

export const pi = 3.14;
export const e = 2.718;

export const square = (x) => {
  return x * x;
};

export const surfaceArea = (r) => {
  return 4 * pi * square(r);
};

Import specific things like so:

import { surfaceArea, square } from './math';

const surfaceOfMars = surfaceArea(3390);
const surfaceOfMercury = surfaceArea(2440);
const yearSquared = square(2017);

'./math' means "from the math.js file located in the same (current) folder".

Or import everything:

import * as mathematics from './math';

const surfaceOfMars = mathematics.surfaceArea(3390);
const surfaceOfMercury = mathematics.surfaceArea(2440);
const yearSquared = mathematics.square(2017);

It means: "import the whole module and call it mathematics in this module". This is why imported things are refered to via mathematics like so: mathematics.surfaceArea.

Default export

You can set one thing to be exported as default.

const pi = 3.14;
const e = 2.718;

const square = (x) => {
  return x * x;
};

const surfaceArea = (r) => {
  return 4 * pi * square(r);
};

export default surfaceArea;

Importing defaults is easy:

import surfaceArea from './math';

const surfaceOfMars = surfaceArea(3390);

Optional reading

  1. Exploring JS: Modules
  2. Understanding ES6 Modules

Lesson transcript

Imagine the settlers building their first small town. It only has few buildings in the beginning: a couple of houses, a post office, and a train station. It is so small that people there can refer to any building by its name: "let's meet at the post office" or "I live in the second house" or "why are you sober, it's already 11 am... let's go... to my house.. number 1".

People were drinking a lot back then. I've heard...

Anyway, as this town grows, more buildings are built. Now the people have a choice:

  • give every new building a unique number or a name
  • divide the town into streets

Of course, they can go with the first option and just keep on giving unique numbers and names to new buildings, so that there are never two buildings number 5. This is fine, I guess, but not too great, especially for a large city. My address is "New York City, building number 654 931". Yeah, this is bad.

Most of the cities go with the second option: they divide the city into streets, usually straight lines, and the building identifiers — names or numbers — are set to be unique within a street. There are many buildings number 5 in a city, but they are all located on different streets, so that's okay.

This is why you have folders on your computer. Without them, all of your files would be in one place, and you could never have two files with the same name. With folders, you only have to keep track of the current folder when creating a new file.

This system of dividing things into streets, blocks or folders allows us to organize things into meaningful modules. Wall street is a street of banking and finance, it's like a module of New York City with a specific purpose. You have a folder called "Videos" and you know it just for videos, a specific type of files.

First programmers were the settlers in this new and weird world of computers. They faced a similar problem and had a choice to make.

They could write all the code in a single file, and this way all the things - string and number constants, variables and functions — must have unique names. And if they want to re-use some code in another project, they have to copy it from this huge file and paste into another file.

Or they can go with the second option: divide the code into smaller modules. Modules can be stored in separate files, and function and constant names will be unique to each file, but not the whole program. And modules can be easily re-used in different projects, without copying and pasting.

Different programming languages have different approaches to this problem. JavaScript is pretty easy: one file equals one module. All the exercises you've done in this course — you've been writing modules.

This is fine, but now we need to somehow connect the code from different files. If you just write code into different files, JavaScript interpreter will not understand how to get stuff from another file.

Let's look at an example: I have a file called "math.js":

const pi = 3.14;
const e = 2.718;

const square = (x) => {
  return x * x;
};

const surfaceArea = (r) => {
  return 4 * pi * square(r);
};

This is my tiny mathematics library.

I create another file called "planets.js":

const surfaceOfMars = surfaceArea(3390);
const surfaceOfMercury = surfaceArea(2440);
const yearSquared = square(2017);

This second file won't work because surfaceArea and square don't exist here. They're in a separate file, but JavaScript doesn't know about it. We have to tell it to look inside another file. This is called "importing" — let's import everything we need:

import { surfaceArea, square } from './math';

const surfaceOfMars = surfaceArea(3390);
const surfaceOfMercury = surfaceArea(2440);
const yearSquared = square(2017);

import keyword, then the list of things we want in curly brackets then the module name. Module name is the same as the filename, but without .js. The file is in the same folder as "planets.js", so this "dot-slash" tells the interpreter to look in the current folder.

When you're importing something from China, what happens in China? Right, exporting. So, our math library should do its part — "exporting":

export const pi = 3.14;
export const e = 2.718;

export const square = (x) => {
  return x * x;
};

export const surfaceArea = (r) => {
  return 4 * pi * square(r);
};

Just put "export" in front of anything you want to export, and this thing will be importable in another file. Here we export everything.

Back to "planets.js". Let's say we want to import more stuff. We can just add names to the list:

import { surfaceArea, square, pi, e } from './math';

Or we can import everything at once:

import * as mathematics from './math';

It says "import the whole module and call it 'mathematics' in this module". Now we have access to everything exported from math module, but we have to refer to all that stuff through 'mathematics' name, like this:

import * as mathematics from './math';

const surfaceOfMars = mathematics.surfaceArea(3390);
const surfaceOfMercury = mathematics.surfaceArea(2440);
const yearSquared = mathematics.square(2017);

mathematics dot something.

Now check this out: if we add a square function right here, it's not going to be a problem:

import * as mathematics from './math';

const square = (x) => {
  return x * x * x;
};

const yearSquared = mathematics.square(2017);   // 4068289
const weirdSaure = square(2017);                // 8205738913

Here the call was made to a square function from the math module, and here the call was made to a local square function.

One last thing: Often you only need to export a single thing from the module. There's a special mechanism called "default export", and you can only export one thing with it. But this default exported thing is easier to import.

const pi = 3.14;
const e = 2.718;

const square = (x) => {
  return x * x;
};

const surfaceArea = (r) => {
  return 4 * pi * square(r);
};

export default surfaceArea;

Just write code as usual, no explicit exports, and in the end, do "export default something". In this case, we export a function surfaceArea.

Importing defaults looks like this:

import surfaceArea from './math';

const surfaceOfMars = surfaceArea(3390);

Exporting and importing mechanisms include more features, like changing the names during importing, multiple types of export from a single module and other things, but you got the most important parts.

In the exercise today you're going to write a module, export, and import a function yourself.