Webbo3 Level 2 · JavaScript Development · Day 6 of 20
Modern JavaScript and Modules
Breaking one enormous file into pieces that each do one job, and the modern features you will read in every codebase you ever open.
By the end of today you can
- Split a project into modules with
exportandimport - Explain why one 800-line file is a problem before it becomes one
- Use shorthand properties, computed keys, methods and rest without looking them up
- Name things so the next person does not have to ask you what they mean
- Reorganise your Day 5 project into files that each do one job
Your Day 5 project probably lives in one file. It works, and at three hundred lines it is still findable. At eight hundred it will not be.
Every team you will ever join solved that problem the same way: many small files, each with one job, that say out loud what they hand out and what they need. Today you learn how.
1. The Problem Modules Solve
Definition
A module is a JavaScript file whose contents are private by default. Nothing inside it can be used by another file unless the module deliberately exports it, and the other file deliberately imports it.
Real-Life Example
A shared office where everyone keeps everything on one big table. Two people both have a folder called "Report", someone moves the wrong one, and nobody can work without bumping into everyone else.
Modules give everyone their own desk with a drawer. You keep your things in your drawer and hand over only what somebody asks for, by name.
The Three Problems of One Big File
- Name clashes: two functions called render, written six weeks apart, silently overwrite each other.
- Everything touches everything: a variable near the top is visible to code four hundred lines below that has no business changing it.
- Nobody can work alongside you: every change by two people to the same file is a conflict.
A module fixes all three at once, because each file only shares what it chooses to.
Picture the office with a desk and a drawer for everyone. Your drawer is private. When a colleague needs something, you hand it over by name, and nothing else leaves your desk.
2. export and import
Definition
export marks something in a module as available to other files. import brings it into another file, naming exactly what it needs and which file it comes from.
Real-Life Example
A restaurant kitchen and its menu. The kitchen can make many things, but only what is on the menu can be ordered. export is putting a dish on the menu; import is ordering it by name.
Types of Export
| Kind | Writing it | Importing it |
|---|---|---|
| Named | export function createTask() {} | import { createTask } from './tasks.js' |
| Several named | export { a, b } | import { a, b } from './file.js' |
| Renamed on import | export { a } | import { a as first } from './file.js' |
| Default (one per file) | export default function () {} | import anything from './file.js' |
| Everything | Any exports | import * as tasks from './tasks.js' |
Type 1: Named Exports
Date.now() gives the number of milliseconds since 1970, which makes a quick, unique-enough id for a task created by hand.
Notice the import path: ./tasks.js. The dot and slash mean "in the same folder as this file", and the .js ending is required in the browser.
Type 2: Default Export
toLocaleString() writes a number with thousands separators, which the next example uses.
A default export can be imported under any name, so the same function ends up called formatNaira in one file and money in another, and searching the codebase for where it is used stops working. Named exports keep one name everywhere.
Common Mistake: Importing Something That Was Never Exported
You forgot type="module" on the script tag. You left .js off the import path. Or you opened the file by double-clicking it (a file:// address), where browsers block modules: use VS Code's Live Server, which you installed last month.
Create a module that exports a function isPassing(score), and use it from another file.
Picture the kitchen and its menu. Everything the kitchen can make stays in the kitchen until it is put on the menu with export. Other files order from the menu by name with import, and cannot walk into the kitchen and take what is not listed.
3. The Modern Syntax You Will Read Every Day
Definition
Since 2015, JavaScript has gained short ways to write things you already know how to do. None of them lets you do anything new; they let you say it with less noise, and every codebase you open uses them.
Real-Life Example
Abbreviations in a message: "ASAP" means the same as "as soon as possible". You need to recognise them to read other people's messages, even if you choose when to use them yourself.
Types
- Shorthand properties: write the name once when the key and the variable match.
- Computed keys: a property name taken from a variable.
- Methods: functions inside an object, without the word
function. - Rest:
...gathering several values into one.
Type 1: Shorthand Properties
Type 2: Computed Keys
Type 3: Methods
A method is a function stored in an object. Inside it, this means "the object this method belongs to", so this.balance reads the object's own balance.
Type 4: Rest
In a parameter list, ...amounts gathers every remaining argument into one array, however many there are.
Rest also works when unpacking: take out the properties you want by name and gather the rest.
In a parameter list, or on the left of =, ... gathers many things into one (rest). Anywhere else it spreads one thing into many (Day 3). Where it sits decides which.
Overall Example
Write a function average(...scores) that works for any number of scores.
Picture shorthand as a signature instead of your full name: same person, less ink. Rest is a bag at the end of the queue that takes everyone who did not get a named seat.
4. Code That Reads Like Sentences
Definition
Naming is choosing names for variables, functions and files that say what they hold or what they do, so code can be understood without its author in the room.
Real-Life Example
Two freezers. One has boxes labelled "stuff", "misc" and "box 2". The other has "chicken", "fish" and "stew, Sunday". Both hold the same food. Only one lets somebody else cook dinner.
Types of Bad Name, and Their Fixes
| Instead of | Write | Because |
|---|---|---|
d, x, temp | daysLeft, student, draft | Nobody can search for x |
data | students, orders | data describes nothing |
check(u) | isEligible(user) | A yes-or-no function should read as a question |
handleClick2 | deleteTask | Name what it does, not when you wrote it |
flag | hasPaid | A boolean should read as a yes or no |
getStuff() | fetchStudents() | "get" suggests it is already here; "fetch" that it is coming from somewhere |
Both return true. Only one of them can be read by a colleague at 6pm on a Friday without asking you what a means.
Picture the labelled freezer. A good name is a label that lets someone who has never met you find exactly what they need, first time.
5. One Job Per File
Definition
The test for whether a file should be split is not its length. It is this: can you describe what the file does in one sentence, without the word "and"? If you need "and", it is two files.
Real-Life Example
In a kitchen, the chef cooks and the cashier takes money. If one person does both, orders slow down and money goes missing. Each job gets its own person, and they pass things between them.
Refactor your Day 5 project into at least three modules along those lines. It must still work exactly as it did. Commit before you start, so you can get back if you break it: that habit is worth more than the refactor.
Almost always one of three things. A function you moved used a variable that stayed behind, so it now needs that value passed in as a parameter. Or you forgot to export it. Or the import path is wrong: ./tasks.js from inside js/, not js/tasks.js. Open the Console: all three produce a specific error that names the thing it could not find. Read it before you change lines at random.
Checkpoint
Q1. Why are named exports preferred over a default export?
A default export can be imported under any name, so the same thing gets different names in different files and searching for its usages stops working.
Q2. import { createTask } from './tasks' fails in the browser. Why?
Browsers require the file extension: ./tasks.js. Bundlers let you leave it off, which is why the habit spreads.
Q3. What is the one-sentence test for splitting a file?
Describe what the file does in one sentence. If you need the word "and", it is doing more than one job and should be two files.
Q4. In function f(first, ...rest), what is rest when you call f(1, 2, 3)?
An array of everything after the first argument: [2, 3].
Tick Before You Move On
- ☐ My Day 5 project is split into three or more modules and still works
- ☐ Every script tag that loads a module carries type="module"
- ☐ Every import path ends in .js
- ☐ I used shorthand properties and rest at least once
- ☐ I renamed at least three badly named things while I was in there
- ☐ I committed before the refactor and again after it
Quick Recap
A module is private by default; only what you export escapes it. type="module", real file extensions and a local server make modules work in the browser. Prefer named exports, so names stay the same and searchable everywhere. Shorthand, computed keys and methods say familiar things with less noise. Three dots gather in a parameter list and spread everywhere else. One job per file, and the test is whether you need the word "and".
Final Scenario
A new developer joins your team and is asked to change how money is displayed. In the one-file version they would scroll through 800 lines hunting for it.
In the modular version they open the one file whose name says it formats money, change one function, and every file that imports it is updated at once.
Small files with clear names, sharing only what they must: that is what makes a codebase something a team can live in.
Tomorrow, Day 7: asynchronous JavaScript. What your code does while it waits for something slow, and why that changes how it is written.