Module 1 ¡ First Programs: The Console, let and const, Types, typeof
Comments, Names and Code a Human Can Read
In this lesson
- Write both comment forms, and make a comment say why the code is there, not what it does.
- Name values, fixed settings and functions by JavaScript's habits, and indent with two spaces.
- Explain what automatic semicolon insertion does, and spot the line that breaks without a semicolon.
Amara and Bob wrote the same twenty-line shop program. Amara's has two comments, and it reads almost like a paragraph. Bob's has a comment on every line, and each one repeats the line next to it: "add 1 to count", above count = count + 1;. Both programs run. A week later, only one of them can be changed safely, and it is not the one with more comments. This lesson is about writing for the second reader of every program: the human.
Two kinds of comment
A comment is text in a program that the engine skips. It is there for people. JavaScript has two forms.
The two comment forms
// a line comment: from the two slashes to the end of the line
/* a block comment:
from slash-star to star-slash, across as many lines as you like */
//starts a comment that ends with the line. Use it for almost everything./*starts a comment that ends at the next*/, however many lines later.- Neither form changes what the program does. The engine throws comments away before it runs a line.
// Delivery fee for one order, in taka.
const fee = 60; // the same in every district this month
/* Free delivery above 1000 taka was tried in August
and stopped, so it is not in this program. */
console.log("Delivery:", fee);
Delivery: 60
Four lines of comments, one line of output: the engine ignored everything after // and between /* and */. A // inside a string is not a comment, so "https://progsity.io" prints whole. So a comment is a note to the reader, in one of two forms, and it never runs.
A good comment says why
The code already says what it does. A comment that repeats it costs the reader time and goes stale when the code changes. Here are Bob's comments.
let count = 0; // set count to 0
count = count + 1; // add 1 to count
console.log(count); // print count
1
Delete all three comments and nothing is lost. A useful comment answers a question the code cannot. Why is it done this way? What would go wrong otherwise? Where does this number come from?
// Prices are kept in paisa, so sums stay exact (lesson 03).
const pencil = 299;
const eraser = 199;
// Divide by 100 only when printing, never before adding.
console.log((pencil + eraser) / 100);
4.98
Both comments explain a decision. Without them, the next person might "simplify" the prices to 2.99 and 1.99 and bring back lesson 03's rounding. So write comments for the why, and let names and layout carry the what.
Names that need no comment
The best way to remove a comment is a better name. const d = 7; needs a comment; const deliveryDays = 7; does not. JavaScript code follows three habits, and the big style guides agree on all of them.
| What it names | Habit | Examples |
|---|---|---|
a value: a let or an ordinary const | camelCase, a noun | totalPrice, itemCount, isMember |
| a fixed setting, known before the program runs | UPPER_SNAKE_CASE | MAX_ITEMS, VAT_RATE, DELIVERY_FEE |
| a function (Module 5) | camelCase, starting with a verb | printReceipt, calculateTotal |
A yes-or-no value reads best with is or has in front, so if (isMember) reads like English. UPPER_SNAKE_CASE is not for every const, only for the few settings a program is built around. const total = a + b; is a const, but it is worked out while the program runs, so it stays camelCase.
Length should match how far the name travels. i is fine for a counter that lives for three lines; a value used across a whole program deserves its full words. So choose names that make a comment unnecessary, in camelCase, with UPPER_SNAKE_CASE for the program's fixed settings.
Indentation and spacing
Code inside { } is pushed in by two spaces, one more step for each level. The engine ignores it completely; people rely on it to see what belongs to what.
const n = 3;
for (let i = 1; i <= n; i++) {
if (i === 2) {
console.log(i, "is the middle one");
} else {
console.log(i);
}
}
1
2 is the middle one
3
This track indents with two spaces, which is the default of Prettier, the code formatter most JavaScript teams run. Prettier's defaults also put spaces around operators, use double quotes and end statements with semicolons. So this track's code looks like what Prettier would print, and you can let it do the spacing for you later.
Semicolons, and the one case that bites
You have seen programs work without semicolons. That is automatic semicolon insertion, or ASI. When a line break comes where the statement cannot go on, the engine puts a semicolon there for you. The rule is about whether the next line can continue the statement. If it can, no semicolon is inserted. One rule runs the other way, and it matters once you write functions (Module 5): a line break straight after return always ends the statement.
A line that starts with ( or [ can always continue the line before it. So the engine joins the two lines, and the result means something nobody wrote. Here is Amara's swap from lesson 02, done in one line with a trick from Module 8, and without semicolons.
let left = "tea"
let right = "coffee"
[left, right] = [right, left]
console.log(left, right)
The program stops with ReferenceError: Cannot access 'right' before initialization, pointing at line 3. The engine read lines 2 and 3 as one statement, shown below. With a semicolon after each line, the same program prints coffee tea.
This is why the track writes every semicolon. It costs one character per line and removes the case entirely. Some teams leave semicolons out on purpose, such as those that follow JavaScript Standard Style. Their rule is to start any line that begins with ( or [ with a semicolon. Both choices work; mixing them by accident is what breaks. So ASI fills in most missing semicolons, and a line starting with ( or [ is the one it gets wrong.
Before and after
Here is Bob's receipt program as he first wrote it. It runs, and its output is right.
let a=3,b=15,c=2,d=20
let x=a*b+c*d // total
x=x+x*0.15 // add
console.log("total",x)
total 97.75
Here is Amara's version, which prints the same line.
// One order: 3 cups of tea and 2 samosas.
const TEA_PRICE = 15;
const SAMOSA_PRICE = 20;
const VAT_RATE = 0.15;
const teaCups = 3;
const samosas = 2;
const subtotal = teaCups * TEA_PRICE + samosas * SAMOSA_PRICE;
// VAT is charged on the whole subtotal, not per item.
const total = subtotal + subtotal * VAT_RATE;
console.log("total", total);
total 97.75
Same output, and every question a reader could ask is answered on the page: which number is a price, which is a count, what 0.15 is, where VAT applies. Bob's // add said nothing his code did not. Amara's comment records a rule from outside the code. So readable code is mostly names and layout, with a comment wherever a decision needs explaining.
A number on its own is a mystery. One comment turns it into a fact.
// 5 minutes of grace before a contest submission is marked late.
const GRACE_MINUTES = 5;
console.log("Grace:", GRACE_MINUTES, "minutes");
Grace: 5 minutes
The name says what the number is. The comment says what it is for, which no name could.
Run in CompilerZara suspects one line is wrong. Instead of deleting it, she turns it into a comment for one run.
let score = 40;
score = score + 25;
// score = score * 2;
console.log("Score:", score);
Score: 65
With the third line commented out, the score is 65; with it back, 130. Putting // in front of a line to switch it off is called commenting it out. Remove such lines before you hand the program in, or the next reader wonders whether they matter.
Kenji's quiz program has two numbers it is built around. He puts them first, in UPPER_SNAKE_CASE, so they are easy to find and change.
const QUESTIONS = 10;
const PASS_MARK = 7;
const correct = 8;
const passed = correct >= PASS_MARK;
console.log(correct, "of", QUESTIONS, "correct");
console.log("Passed:", passed);
8 of 10 correct
Passed: true
>= means "at least", and gives true or false. If the pass mark changes to 6, there is one line to edit, and its name says which.
The program that crashed in the ASI section, with one semicolon per line.
let left = "tea";
let right = "coffee";
[left, right] = [right, left];
console.log(left, right);
coffee tea
The semicolon at the end of line 2 ends that statement, so line 3 is read on its own. Its square brackets swap the two values; Module 8 explains how.
Run in CompilerWhere this is used
- The Airbnb and Google style guides. Both ask for camelCase names and semicolons. Google's names a true constant in CONSTANT_CASE, its word for UPPER_SNAKE_CASE.
- Prettier. The formatter rewrites a file's layout on save: two-space indents, double quotes, semicolons and an 80-character line by default. The React and Next.js repositories format their code with it.
- ESLint. A linter reads code without running it and reports likely bugs and broken habits, such as a name that is declared and never used. This track does not teach it, but most teams run it next to Prettier.
Common mistakes
1. A block comment that never closes.
/* the price list
const price = 450;
console.log(price);
The program does not start: SyntaxError: Invalid or unexpected token. Everything after /* is comment until a */, and there is none. Close it with */, or use // on each line instead. You will leave it open when you add a long note and plan to finish it later.
2. A block comment inside a block comment.
/* outer note /* inner note */ still outer */
console.log("hi");
The program does not start: SyntaxError: Unexpected identifier 'outer'. The first */ ends the whole comment, and the engine tries to read still outer */ as code. Block comments do not nest. You will hit this when you comment out a block that already holds a comment.
3. A comment that lies.
// VAT is 10%.
const VAT_RATE = 0.15;
No message, ever. The rate changed, and the comment did not. The next reader trusts the comment and gets every sum wrong by hand. When you change code, read the comments next to it, and delete a comment you will not keep true. You will miss it because a comment never fails a run, so nothing reminds you.
4. A line that starts with a bracket, after a line with no semicolon.
const label = "Total:"
(120 + 45)
TypeError: "Total:" is not a function. The engine joined the lines into "Total:"(120 + 45), a call on a string. End line 1 with a semicolon. You will see this only after deleting a semicolon, which is why this track never deletes them.
David wrote this program for a book stall. It works, and nobody else can read it. Rewrite it with good names, fixed settings in UPPER_SNAKE_CASE, two-space indents, semicolons and at most two comments that say why. It must print exactly the same two lines.
Output. Exactly these two lines.
books 3 cost 540
after discount 486
let q=3,p=180
let t=q*p
console.log("books",q,"cost",t)
let t2=t-t*0.1 // minus
console.log("after discount",t2)
Not graded: a judge sees only the output, and the point here is the code. Compare yours with Amara's receipt in "Before and after".
Run in CompilerMaria wants the multiplication table of n with the columns lined up. Each of the ten lines reads n x i = p. The i is padded on the left to 2 characters, and p to as many characters as n * 10 has. String(x).padStart(w) gives x as text, with spaces added on the left until it is w characters long; Module 3 covers it.
Input. One whole number n.
Output. Ten lines, for i from 1 to 10.
Sample. Input 7 gives these lines, from 7 x 1 = 7 to 7 x 10 = 70.
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
const input = require("fs").readFileSync(0, "utf8");
const tokens = input.split(/\s+/).filter(Boolean);
let at = 0;
const next = () => tokens[at++];
const nextInt = () => Number(next());
const out = [];
// your code: read with next() and nextInt(), push every line of output to out
// Work out the width of n * 10 once, before the loop.
// Then, for i from 1 to 10, push one padded line.
console.log(out.join("\n"));
Graded as times-table. The hidden tests include n = 1 and the largest n the statement allows.
Common doubts
Do comments make the program slower?
No. The engine drops them when it reads the file, before anything runs. Websites often strip them anyway, with a tool called a minifier, to send fewer bytes to the browser.
Tabs or spaces?
Either works for the engine. This track uses two spaces, Prettier's default, and the one rule that matters is to be the same as the rest of the file.
If ASI exists, why not leave semicolons out?
Some teams do, with a rule for lines that start with
(or[. This track writes them so that you never need that rule. Pick one style per project and keep to it.How many comments is the right number?
As many as there are decisions a reader cannot see from the code. In a short program with good names, that is often none, or one at the top saying what the program is for.
Key takeaways
//comments to the end of the line;/* */spans lines and does not nest.- A good comment says why; the code and its names already say what.
- camelCase for values, UPPER_SNAKE_CASE for fixed settings, a verb first for a function.
- Two spaces per level of
{ }, Prettier's default, and spaces around operators. - ASI inserts a semicolon at a line break where the next line cannot continue the statement, and always after
return. - A line starting with
(or[joins the line before it, so this track writes every semicolon.
Next comes the problems page: ten problems on the starter from lesson 05, graded by a judge that reads only your output.
End of lesson 6
Mark it done, and your progress moves with you.
Next: Problems: First Programs