Chapter 2 · Decide, repeat, reuse
Modules and input
Step 1 of 22 · Concept
A module is a file of functions
By the end of this lesson your programs span several files, and read files and input.
Each .js file is a module. shapes.js writes export before its function, so other files may use it.
main.js takes it with import:
import { area } from "./shapes.js";
./ means this folder, and the .js is required. Write import lines at the top of the file.
Step 2 of 22 · Quiz
Which import works?
main.js and shapes.js are in one folder. Which line in main.js imports area?
Step 3 of 22 · Demo
Two files, one program
One import can take several names: { area, perimeter }. Run it, then open shapes.js in its tab.
Step 4 of 22 · Concept
A wrong import stops everything first
A wrong import stops the program before its first line runs. A missing .js, from "./shapes", prints:
node:internal/modules/run_main:107
triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../shapes' …
Did you mean to import "./shapes.js"?
This message starts in Node's own code, not in your file. Read its Error line and the Did you mean line.
A function without export stops with SyntaxError: The requested module './shapes.js' does not provide an export
named 'area'. Read it as in lesson 5: it points at main.js:1, the import line.
Step 5 of 22 · Try it
Try it: the missing export
Run it: SyntaxError: The requested module './shapes.js' does not provide an export named 'perimeter'. Not one line
of main.js ran.
Open shapes.js and add the missing word. The program must print:
6 10
In shapes.js, perimeter needs export before function, as area has.
Step 6 of 22 · Concept
A module runs once
- Node reads and checks every file a program imports before any line runs. So a
SyntaxErrorinshapes.jsstops the program before the first line ofmain.js. - Then each module runs once, at its first import, even when two files import it. A module's imports run before its own lines.
Step 7 of 22 · Quiz
How many times?
main.js imports greet.js and shapes.js, and greet.js imports shapes.js too. What does Run print?
shapes.js:
console.log("shapes runs");
export function area(w, h) {
return w * h;
}
greet.js:
import { area } from "./shapes.js";
console.log("greet runs");
export function greet(name) {
return `Hello, ${name}`;
}
main.js:
import { greet } from "./greet.js";
import { area } from "./shapes.js";
console.log(greet("Ada"), area(2, 3));
console.log("shapes runs");
export function area(w, h) {
return w * h;
}import { area } from "./shapes.js";
console.log("greet runs");
export function greet(name) {
return `Hello, ${name}`;
}import { greet } from "./greet.js";
import { area } from "./shapes.js";
console.log(greet("Ada"), area(2, 3));Step 8 of 22 · Demo
See it run
Run it and compare with your answer: shapes runs prints once, first. Then open the three files' tabs.
Step 9 of 22 · Concept
What every program has
Some names are in every program, with no import. A module of Node's, such as node:fs, you import first:
| name | what for | import it? |
|---|---|---|
Math | numbers: Math.floor, Math.round | no: built in |
console | console.log | no: built in |
JSON | data as text (lesson 11) | no: built in |
node:fs | Node's module for files | yes |
Step 10 of 22 · Concept
Math.random gives a new number each run
Math.random() gives a number from 0 up to 1, never 1 itself. It is new on every run, and JavaScript has no way to
fix it in advance. A dice roll, from 1 to 6:
const roll = Math.floor(Math.random() * 6) + 1;
| part | gives, for example |
|---|---|
Math.random() | 0.73: from 0 up to 1 |
* 6 | 4.38: from 0 up to 6 |
Math.floor(...) | 4: a whole number from 0 to 5 |
+ 1 | 5: from 1 to 6 |
So a program whose output must match never prints a roll. It prints a fact about it, such as In range: true.
Step 11 of 22 · Demo
Roll a die
Run it: In range: true. Then add console.log(roll); as a last line and press Run a few times: the roll changes.
Step 12 of 22 · Concept
Read a file by its name
import { readFileSync } from "node:fs";
const names = readFileSync("names.txt", "utf8").trim();
readFileSyncreads a whole file as one text."utf8"says how its bytes become text."names.txt"is a file of the folder where Run runsnode: the block's folder.- A text file ends with a line end,
\n..trim()removes spaces and line ends from both ends of a text.
Step 13 of 22 · Demo
See it read
Run it: two names and Characters: 8. Remove .trim() and run it again: an empty line, and 9, for the line end.
Then add a name to names.txt in its tab, and run it.
Step 14 of 22 · Concept
The Terminal shows what Run uses
In See it read, choose Open in the terminal in the ⋯ menu. The Terminal opens in that block's folder:
| you type | it does |
|---|---|
ls | lists main.js and names.txt |
cat names.txt | shows the file's text |
node main.js | runs it, as Run does |
cat /home/package.json | shows { "type": "module" } |
That file makes every program here a module. A module runs in strict mode: some silent slips become errors. totl = 5; with no let stops with ReferenceError: totl is not defined.
Step 15 of 22 · Concept
Input is a file too
import { readFileSync } from "node:fs";
const age = readFileSync(0, "utf8").trim();
0is the number of the program's input.readFileSync(0, "utf8")reads all of it as one text.- A block's input is given in advance; its task shows it. In the Terminal, you type it, press Enter, then Ctrl-D.
Step 16 of 22 · Quiz
What does input + 1 give?
The input is 15. What does this program print?
import { readFileSync } from "node:fs";
const age = readFileSync(0, "utf8").trim();
console.log(age + 1);
Step 17 of 22 · Demo
See it run
The input is 15. Run it and compare with your answer.
Step 18 of 22 · Try it
Try it: next year
The input is 15. Run it: Next year: 151. Turn the input into a number with Number(...) (lesson 4), so the
program prints:
Next year: 16
Wrap the read in Number(...): Number(readFileSync(0, "utf8").trim()). Then age holds the number 15.
Step 19 of 22 · Exercise
Your turn: a tip module
The input is a bill, 50.
- In
money.js, exporttip(bill, percent), which returnsbill * percent / 100. - In
main.js, read the bill from the input, as a number. - Log
Tip:and the tip at 20 percent, thenTotal:and the bill plus the tip.
The program must print:
Tip: 10
Total: 60
Input is text. Without Number(...), the bill plus the tip joins: Total: 5010.
money.js holds export function tip(bill, percent) with one return. main.js starts with two imports: readFileSync from "node:fs" and tip from "./money.js".
const bill = Number(readFileSync(0, "utf8").trim());
Step 20 of 22 · Check yourself
Check yourself: a shop
No starter code this time. The input is a quantity, 12.
- In
shop.js, exportcost(qty): 3 for each item, and 5 off from 10 items on. - In
main.js, read the quantity from the input. - Log the quantity and its cost. The output must be:
12 items: 31
Two files, as in the tip exercise: shop.js exports the function; main.js imports it, reads the input and logs. In cost, an if takes the 5 off.
Step 21 of 22 · Challenge · optional
Challenge: one name for a module
Optional.
main.js calls every function of shapes.js through one name, shapes. Make it work:
- In
shapes.js, addsquare(side), exported, which returnsarea(side, side). - In
main.js, import all ofshapes.jsunder the one nameshapes.
The program must print:
6 10
16
Run it first: ReferenceError: shapes is not defined. No box named shapes exists until an import makes it.
import * as shapes from "./shapes.js"; puts every export of the file under one name: shapes.area, shapes.perimeter and your square.
export function square(side) {
return area(side, side);
Step 22 of 22 · Recap
Recap
- Each
.jsfile is a module.exportshares a function;import { area } from "./shapes.js"takes it. - Node checks every imported file first. Then each module runs once, at its first import.
Mathandconsoleare built in;node:fsis imported.Math.random()is new each run.readFileSync("names.txt", "utf8")reads a file as text;readFileSync(0, "utf8")reads the input.- Input is text:
.trim()it, thenNumber(...)it.
Next: lesson 9 works with text: characters, slices and lines.
Review
3 questions from this lesson, in a new order each time. Answer from memory: 2 of 3 right on the first try passes. On a day after you finish the lesson, a pass earns 15 XP.
The review needs JavaScript.
import { area, perimeter } from "./shapes.js";
console.log(area(2, 3), perimeter(2, 3));
import { area, perimeter } from "./shapes.js";
console.log(area(2, 3), perimeter(2, 3));
import { greet } from "./greet.js";
import { area } from "./shapes.js";
console.log(greet("Ada"), area(2, 3));
const roll = Math.floor(Math.random() * 6) + 1;
console.log("In range:", roll >= 1 && roll <= 6);
import { readFileSync } from "node:fs";
const names = readFileSync("names.txt", "utf8").trim();
console.log(names);
console.log("Characters:", names.length);
import { readFileSync } from "node:fs";
const age = readFileSync(0, "utf8").trim();
console.log(age + 1);
import { readFileSync } from "node:fs";
const age = readFileSync(0, "utf8").trim();
console.log("Next year:", age + 1);
// 1. import tip from money.js
// 2. read the bill from the input
// 3. log Tip: and Total:
// read the quantity, then log its cost
// import all of shapes.js as shapes
console.log(shapes.area(2, 3), shapes.perimeter(2, 3));
console.log(shapes.square(4));