Statements, comments & semicolons
Learn how JavaScript reads code line by line: statements, expressions, blocks, semicolons, comments, and the whitespace rules that matter.
- 01Read code as instructionsTell a statement (a complete instruction) from an expression (code that makes a value).
- 02Group code safelyUse braces to make blocks, and know when braces make an object instead.
- 03Avoid line-break mistakesUse semicolons, comments, and spacing on purpose, and spot the line breaks that change what code does.
Watch the video lecture
Full course on YouTube (opens in a new tab) ↗- Lecture 8Comments in JavaScriptWatch on YouTube (opens in a new tab) ↗
How JavaScript reads your code
A JavaScript file is a list of instructions. JavaScript reads them from top to bottom, one after another. In an earlier lesson, you saw that a program is like a recipe: a list of steps done in order. This lesson is about how each step is written. You will learn about:
- Statements: complete instructions, like one step of a recipe.
- Expressions: smaller pieces inside a statement that make a value.
- Braces,
{ }, which group several steps together. - Semicolons,
;, which mark where a step ends. - Comments and spacing, which help people read the code.
First you will see tiny programs. Then you will see four common mistakes:
returnwith its value on the next line.- A missing semicolon before a line that starts with
[. - An extra semicolon right after
if (...). - Braces that look like an object but are not one.
A statement is like a complete sentence. It tells JavaScript to do one thing. An expression is like a phrase, a few words that are not a full sentence. It makes a value. That value can then be used inside a statement. For example, the phrase 2 + 3 makes the value 5. The statement let score = 2 + 3; keeps that value under the name score.
- In real life: A complete sentence: “Put the mug on the table.”
- In JavaScript: A statement:
let score = 5; - In real life: A phrase: “the blue mug”
- In JavaScript: An expression:
2 + 3,score, orx > 2 - In real life: A phrase can sit inside a sentence
- In JavaScript: An expression can sit inside a statement
A statement is a complete instruction. An expression is a piece of code that makes a value. A statement can hold expressions inside it. An expression can also stand alone as a statement. You do that when the expression does something useful, like printing with console.log.
Statements vs expressions
INTERACTIVETo tell them apart, ask one question:
- For an expression, ask: what value does this make?
- For a statement, ask: what instruction does this give?
One line can have both. In let x = 5 + 3;, the whole line is a statement. It is a declaration: a statement that makes a new name, here x. The part 5 + 3 is an expression inside it.
const teaPrice = 3;const total = teaPrice + 2;console.log(total);Line 1 makes teaPrice and gives it the value 3. Line 2 is another declaration. First the expression teaPrice + 2 makes 5. Then the statement stores 5 in total. Line 3 calls console.log, which prints 5.
teaPrice + 2 is an expression. It makes a value, 5. Then the statement puts that value in total.let cartTotal = 0;
cartTotal = 3 + 2;
console.log(cartTotal);Line 1 starts cartTotal at 0. Line 2 is an assignment: a statement that gives a name a new value with =. The right side, 3 + 2, is an expression. It makes 5, and 5 replaces the old value. Line 3 prints 5.
const drink = "tea";
const label = drink.toUpperCase();
console.log(label);Line 2 calls toUpperCase(), which turns text into capital letters. The call is an expression, because it makes a value: "TEA". Line 3 prints that value. So a call does not only do things, like printing. It can also give back a value.
The table below sums up four kinds of code. Read each row as: "to spot this kind of code, ask this question."
| Kind of code | Question to ask | Tiny example | What JavaScript does with it |
|---|---|---|---|
| Expression | What value does this make? | 2 + 2 | It works out the value 4. |
| Statement | What instruction does this give? | let total = 4; | It does one complete step of the program. |
| Block | Which statements are grouped in braces? | { console.log(total); } | It runs the grouped statements in order. |
| Comment | What note helps people? | // explain why | Nothing. It skips the comment. |
Now sort these cards. Look closely at console.log("hi");. The call is an expression, but we write it as a whole line because we want it to print. Doing something besides making a value, like printing, is called a side effect.
let x = 5;5 + 3x > 2if (x) {}"hello"for (...) {}console.log("hi");;
Put each card in its group. If a whole line is just an expression that we write so it does something, like printing, choose Expression used as statement.
Later lessons use these words a lot:
- The condition of an
if, inside its round brackets, is an expression. - The code that an
ifruns is a statement. - The line
"use strict";in the next lesson is an expression used as a statement. It has a special name: a directive.
Expressions as whole lines, and the empty statement
STEP THROUGHSome expressions can stand alone as a whole line. Then they count as a statement. A few examples:
score;is allowed, but it is almost never useful. It only reads the value and does nothing with it.console.log(score);is useful, because the call prints something.- A semicolon on its own,
;, is allowed too. It is the empty statement: a complete instruction that does nothing on purpose.
A statement is a complete instruction. An expression is a piece of code that makes a value, often inside a statement.
script
score;console.log("score:", score);;The player shows a completion value for each line. That is the result JavaScript notes down after it runs a statement. You don't see it in a normal program. Some tools show it, like the browser console and Node's vm.runInContext. A completion value is not printed output. console.log prints text on the screen, but its own value is undefined.
; on its own does nothing. That sounds harmless. But look at if (isReady);. Now the if controls only the empty statement. The block after it is not part of the if, so it runs every time. You will fix this exact bug in the exercises.
Blocks: braces that group statements
STEP THROUGHA block statement, or block, is a group of statements inside braces, { }. You will see blocks after if, after for, in functions, and in many other places. The braces only group the statements. They don't make a value, and they don't pause anything. The statements inside still run in order, from top to bottom.
If statements are sentences, a block is a paragraph. It holds several sentences that belong together. From the outside, a paragraph is one piece of the page. In the same way, a block counts as one statement.
- In real life: A paragraph groups sentences that belong together
- In JavaScript: A block groups statements that belong together
- In real life: You still read the sentences in order
- In JavaScript: The statements inside still run from top to bottom
- In real life: You can move a paragraph as one piece
- In JavaScript: A block can be the code an
if, afor, or a function runs
A block groups statements and runs them in order. Step through it line by line.
script
{ const message = "inside"; console.log(message);}console.log("after block");Look at const message. It is made inside the block. A name made with let or const inside braces belongs to that block. Code outside the braces can't use it. You will learn the full rules later, in the lessons on scope. For now, remember: braces often make a small room for names.
const hasItems = true;
if (hasItems) {
console.log("Show checkout");
}
console.log("Page ready");Line 2 checks hasItems. It is a boolean: a value that is either true or false. Here it is true, so line 3 runs and prints Show checkout. The block ends on line 4. Then line 5 prints Page ready. If hasItems were false, JavaScript would skip only the block. Line 5 would still print Page ready.
{ const drink = "tea"; console.log(drink);}console.log(typeof drink);Line 2 makes drink inside the braces. Line 3 prints tea. Line 5 is outside the block. It uses typeof, which tells you the type of a value as text. typeof is safe to use on a name that doesn't exist: it gives "undefined" instead of an error. So line 5 prints undefined. That shows drink can't be used outside its block.
When { starts a block, not an object
INTERACTIVEBraces have two jobs in JavaScript:
- They can start a block, as you just saw.
- They can make an object: a value that holds named things, like
{ name: "Asha" }.
Where the braces are decides the job. At the start of a statement, { a: 1 } starts a block, not an object. Inside that block, a: is a label: a name with a colon, put in front of a statement. Labels are rare; you only need to know they exist. The 1 after the label is an expression used as a statement. So the completion value of the whole line is 1.
{ a: 1 } is a block, so no object is made. Inside round brackets, JavaScript expects a value, so ({ a: 1 }) makes an object.{ a: 1 };({ a: 1 });(() => { a: 1 })();(() => ({ a: 1 }))();At the start of a statement, braces start a block. Inside it, a: is a label and 1 is a statement, so the result is 1.
{ a: 1 } typed on its own as an object, to be helpful.const user = { name: "Asha" };
console.log(user.name);Here the braces come after =. After =, JavaScript expects a value, so the braces make an object. No round brackets are needed. Line 2 reads the object's name and prints Asha. You only need round brackets when an object is at the very start of a statement.
Chrome DevTools and some other browser consoles try to help you. If you type { a: 1 } on its own there, they may show it as an object. A real script reads the same text, at the start of a statement, as a block. Write ({ a: 1 }) when you mean an object.
Arrow functions have the same problem. An arrow function is a short way to write a function, like () => 5. In () => { a: 1 }, the braces after => are the function's block. There is no return, so it gives back undefined. To give back an object, wrap it in round brackets: () => ({ a: 1 }).
Semicolons, and when JavaScript adds them for you
STEP THROUGHA semicolon, ;, marks the end of a statement. If you leave one out, JavaScript can sometimes add it for you at a line break. This is called automatic semicolon insertion, or ASI for short. ASI is like autocorrect on your phone. It usually helps, but sometimes it guesses wrong.
You forget a period in a text message, and autocorrect adds one. Usually that helps. Sometimes it changes what you meant. ASI does the same for code. It follows fixed rules. It can't know what you meant.
- In real life: A period ends a sentence
- In JavaScript: A semicolon ends a statement
- In real life: Autocorrect adds a missing period
- In JavaScript: ASI adds a missing semicolon at some line breaks
- In real life: Autocorrect can guess wrong
- In JavaScript: ASI can join two lines into one, or end
returntoo early
First mistake: some lines can join onto the line before them. This happens when a line starts with [, (, or a backtick (`, used for template strings). JavaScript then reads the two lines as one statement. Switch the semicolon on and off below. In Chrome and Node, the version without it throws this error: TypeError: Cannot read properties of undefined (reading 'forEach'). Other browsers may word the message differently. The error type, TypeError, is the same.
Switch the semicolon at the end of line 1 on or off. Guess first: does line 2 start a new statement, or join onto line 1?
script
[1, 2].forEach((n) => console.log(n));Second mistake: a line break right after return. The function below really gives back undefined. ASI adds a semicolon right after return, so the function stops there. The object on the next lines is never returned.
function makeCard() { return { title: "JavaScript" };}console.log(makeCard());To fix it, put the object on the same line as return.
This function gives back undefined. ASI adds a semicolon right after return, so the object on the next lines is never returned.
; right after return, so the function stops there and gives back undefined. On the right, the object is on the same line, so it is returned.function makeCard() { return { title: "JavaScript" };}console.log(makeCard().title);Line 2 keeps return and the object on the same line. So the function gives back the object, and line 4 prints its title: JavaScript. This is the normal way to return an object from a function.
While you are learning, end every statement with a semicolon. Never put the value of return on the next line. If a line starts with (, [, or a backtick, make sure the line before it ends with a semicolon.
Where you'll use this
You will use these ideas in almost every program:
- The code inside a function is a list of statements.
- Conditions are expressions.
if, loops, and functions use blocks.- Comments explain choices that are not obvious.
- Semicolons and neat spacing show readers where each statement ends, so nobody has to guess.
// Keep related steps together.if (message.trim() !== "") { const loud = message.toUpperCase(); console.log(loud);} // Start lines with [ safely after a statement.const count = 1;["ready"].forEach((word) => console.log(word));Line 2 uses an expression as the condition of the if. The braces from line 2 to line 5 make a block. Line 8 ends with a semicolon, so line 9, which starts with [, is a new statement. The comments on lines 1 and 7 explain the reason for the code. They don't say the obvious, like "console.log prints".
const message = " hello ";
const cleanMessage = message.trim();
if (cleanMessage !== "") {
console.log(cleanMessage.toUpperCase());
}Text typed into a form often has extra spaces. Line 2 uses trim(), which removes spaces from both ends. It gives "hello". Line 3 checks that this text is not empty, so line 4 prints HELLO. This way, an empty form field never sends an empty message.
The next lesson, Strict mode, starts with the line "use strict";. That line is a directive: an expression used as a statement, at the top of a script or function, that turns on a special mode. You don't need the strict-mode rules yet. Just notice that you can now read how the line is built.
Common misconceptions
“Expressions are only math.”
Text, comparisons, reading a property, and function calls are expressions too. They all make a value.
“Semicolons are always optional.”
ASI often adds them for you. But without a semicolon, a line that starts with [, (, or a backtick can join the line before it.
“Braces always make an object.”
At the start of a statement, braces start a block. Wrap them in round brackets when you want an object.
“Indenting code makes a block.”
Braces make a block. Indenting, the space at the start of a line, only helps people read.
“A block comment can go inside another one.”
A block comment ends at the first */. If you put one /* ... */ inside another, the outer one ends too early.
The table below lists code that looks like one thing but is another. Read each row as: "this looks like X, but it really is Y, so do Z."
| When you see | What it really is | What to do instead |
|---|---|---|
{ a: 1 } at the start of a statement | A block with a label inside, not an object. | Write ({ a: 1 }) when you want an object. |
return, a line break, then an object | The function returns undefined. The code below return never runs. | Keep the value on the same line as return. |
if (ready); { ... } | The if controls only the empty statement ;. The block always runs. | Delete the semicolon after if (ready). |
// inside quote marks | Plain text, not a comment. | Remember: only // outside quote marks starts a comment. |
Practice: read the structure
6 EXERCISESSix exercises, from easy to harder. Try each one before you open the hints.
Which one is an expression: if (x) {} or x > 2?
x > 2 is the expression, because it makes a value: true or false. if (x) {} is a statement. It decides whether other code runs.
What exactly does this program print?
function label() {
return
{
text: "done"
};
}
console.log(label());It prints undefined. The function stops at return on line 2, so the braces below are never returned.
In Chrome and Node, this code throws an error. Add one character so it prints the two numbers in the list. What does it print then?
const a = 1
[1, 2].forEach((n) => console.log(n));const a = 1;
[1, 2].forEach((n) => console.log(n));The semicolon ends line 1. Now line 2 is a separate statement, and it prints 1 and then 2.
This program prints its message even though isReady is false. Which character causes that?
let isReady = false;
if (isReady);
{
console.log("Running anyway");
}let isReady = false;
if (isReady) {
console.log("Running only when ready");
}The semicolon after if (isReady) was the empty statement. So the if controlled nothing useful. Without it, the if controls the block.
What should you wrap around { a: 1 } so JavaScript makes an object?
console.log(({ a: 1 }).a);Round brackets (parentheses) make the braces an object. Then .a reads the value of a and prints 1.
Pick a small piece of your own code. Add one comment that says why it is there. Don't just repeat the code in English.
// Keep the first item as a featured card for the layout.
const featured = items[0];The comment gives the reason for taking the first item. JavaScript skips it, but now a person knows why the code is there.
Quiz: check your understanding
8 QUESTIONSAnswer each question before you open its explanation. For code questions, run the code in your head one statement at a time. Every answer was checked by running real JavaScript.
Question 1 of 8Which sentence best describes an expression?
Choose an answer to see the explanation.
Question 2 of 8What does this print?
Read the code, then predictlet score = 2 + 3; console.log(score);Choose an answer to see the explanation.
Question 3 of 8What is
;on its own?Choose an answer to see the explanation.
Question 4 of 8What does this program print?
Read the code, then predictlet ok = false; if (ok); { console.log("surprise"); }Choose an answer to see the explanation.
Question 5 of 8In a real script, what is
{ a: 1 }at the start of a statement?Choose an answer to see the explanation.
Question 6 of 8This function has a line break right after
return. What does it print?Read the code, then predictfunction makeCard() { return { title: "JavaScript" }; } console.log(makeCard());Choose an answer to see the explanation.
Question 7 of 8Which kind of comment can cover more than one line?
Choose an answer to see the explanation.
Question 8 of 8Which spacing choice can change what the code does?
Choose an answer to see the explanation.
Key takeaways
- A statement is a complete instruction. An expression makes a value.
- An expression can be a whole line. That is useful when it does something, like
console.logprinting. - A block is a group of statements in braces. Names made with
letorconstinside it stay inside it. - At the start of a statement, braces make a block. Wrap them in round brackets when you want an object.
- ASI adds some missing semicolons. Watch out after
return, and before lines that start with(,[, or a backtick. - Comments are for people. Spacing is mostly for people too, and formatters keep it neat.
Remember the one-liner.
Code is a list of statements. Expressions make the values inside them. Semicolons and braces show where each one ends.
To look at the big picture again, go back to Why JavaScript?. Coming next: Strict mode.
Comments, spacing, and formatting
A comment is a note in your code for people. JavaScript skips comments; they never run. Use a comment to say why the code does something. It can also be a short note for whoever reads the code later. Don't use a comment to repeat what the code already says.
A good note helps a person understand what you wanted to do. It doesn't make the computer do anything new.
Line by line:
//.page, so the output ishttps://completefrontend.com. The comments don't change it.The rules for each kind of comment:
//starts a one-line comment. It ends at the end of the line./* ... */is a block comment. It can cover several lines. You can't put one block comment inside another./** ... */is a JSDoc comment. It is still a block comment, but code editors read it to show help about a function.//inside quote marks is part of the text, not a comment.The comment on line 1 gives a reason. It doesn't describe the code on the next line. JavaScript skips line 1. It sees that
signedInistrue, and printsWelcome, Asha. Avoid comments like// set signedIn to true. The code already says that.Whitespace means spaces, tabs, and line breaks. It works like the spaces between words. Most whitespace helps people read, but it doesn't change what the code means. For example,
2+2and2 + 2are the same expression. Tools called formatters, like Prettier, fix the spacing for you so it looks the same everywhere. You have already seen the two exceptions: a line break right afterreturn, and a line break before a line that can join the line above.Line 1 has no spaces around
=. Line 2 has spaces around=and+. Both lines work, and line 3 prints5. Write it the second way. JavaScript gets the same values either way, but people find spaced code easier to read.