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 statements from expressions and trace their completion values.
- 02Group code safelyUse blocks, recognize labels, and return object literals from arrow functions.
- 03Avoid formatting trapsUse semicolons, comments, and whitespace intentionally.
How JavaScript reads your code
A JavaScript file is not a cloud of symbols. It is a sequence of instructions read from top to bottom. Earlier you met the idea that a program is a recipe: a list of steps run in order. This lesson zooms in on the shape of those steps: statements, the value-producing pieces inside them called expressions, the braces that group steps, and the punctuation and spacing that make the recipe unambiguous.
You will see tiny programs first, then the traps professional developers still watch for: return on its own line, a missing semicolon before [, a stray semicolon after if, and braces that look like an object but start a block.
Think of a statement as a complete sentence: it tells JavaScript to do one thing. An expression is more like a phrase: it produces a value that can be used inside a larger sentence. The phrase 2 + 3 becomes the value 5; the statement let score = 2 + 3; stores that value in a name.
- 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
Where the analogy stops: Human sentences can be fuzzy and poetic. JavaScript grammar is strict: the engine must be able to parse one exact structure.
A statement is a complete instruction. An expression is code that produces a value. A statement may contain expressions, and an expression can be used as a statement when you care about its side effect.
Statements vs expressions
INTERACTIVEThe fastest test is a question. For an expression, ask: what value does this produce? For a statement, ask: what instruction does this give? The same line can contain both. In let x = 5 + 3;, the whole line is a declaration statement, while 5 + 3 is an expression inside it.
| Piece | Question to ask | Tiny example | What JavaScript gets |
|---|---|---|---|
| Expression | What value does this produce? | 2 + 2 | The value 4 |
| Statement | What instruction does this give? | let total = 4; | A completed step in the program |
| Block statement | Which statements are grouped? | { console.log(total); } | A group that runs in order |
| Comment | What note helps humans? | // explain why | Nothing at runtime |
Sort these cards. Pay special attention to console.log("hi"): the call expression produces a value, but we normally write the whole line for its side effect, printing.
let x = 5;5 + 3x > 2if (x) {}"hello"for (...) {}console.log("hi");;
Place each card where it belongs. If a call expression is being used as a whole line for its side effect, choose expression used as statement.
This distinction matters because later lessons build on it. Conditions in if statements are expressions. The body of an if is a statement. The line "use strict"; in the next lesson is a special expression statement called a directive.
Expression statements and the empty statement
STEP THROUGHJavaScript allows some expressions to stand alone as statements. A bare score; line is legal, although it is rarely useful in a program. A call such as console.log(score); is useful because calling it prints something. A lone semicolon is also legal: it is the empty statement, a complete instruction that intentionally does nothing.
Statements are complete instructions. Expressions are the value-producing pieces that can live inside those instructions.
script
score;console.log("score:", score);;The player mentions completion values. When a script evaluates a statement, JavaScript internally tracks a completion. Browser consoles and Node's vm.runInContext can show that value, but it is separate from printed output. console.log prints because of a side effect; its own result is undefined.
; by itself does nothing. That sounds harmless, until you accidentally write if (isReady);. Then the if controls the empty statement, and the block after it runs every time. You will fix exactly that bug in the exercises.
Block statements
STEP THROUGHA block statement is a group of statements wrapped in braces. You will see blocks after if, for, functions, and more. The braces are not themselves a pause or a value; they group the statements between them, which still run in order.
If statements are sentences, a block is a paragraph: several related instructions bundled together. The paragraph analogy is useful because it reminds you that a block is still one statement from the outside.
- In real life: A paragraph groups related sentences
- In JavaScript: A block groups related statements
- In real life: Sentences still read in order
- In JavaScript: Statements inside still run top to bottom
- In real life: A paragraph can be moved as one unit
- In JavaScript: A block can be the body of
if,for, or a function
Where the analogy stops: Paragraphs do not create variable scope. JavaScript blocks do for let and const, which later lessons explore more deeply.
A block statement groups statements and runs them in order. Step through the paragraph of code.
script
{ const message = "inside"; console.log(message);}console.log("after block");Notice that const message is inside the block. With let and const, names belong to the block that creates them. You do not need the full scope rules yet; just remember that braces often make a small room for names.
When { starts a block, not an object
INTERACTIVEBraces are overloaded. They can start a block statement, or they can be part of an object literal expression. Context decides. At the start of a statement in a real script, { a: 1 } starts a block. Inside that block, a: is a label, and 1 is an expression statement. The script completion value is 1.
{ a: 1 }({ a: 1 })(() => { a: 1 })()(() => ({ a: 1 }))()At statement start, braces begin a block. The label a: points at expression 1, so a script completion can be 1.
{ a: 1 } typed alone as an object for convenience.Chrome DevTools and some other browser consoles try to be helpful: when you type { a: 1 } alone, they may treat it as an object expression. A real script parses the same text at statement start as a block. Use ({ a: 1 }) when you mean an object expression.
Arrow functions have the same issue. () => { a: 1 } has a block body and returns undefined. To return an object immediately, wrap the object in parentheses: () => ({ a: 1 }).
Semicolons and automatic insertion
STEP THROUGHSemicolons mark statement endings. JavaScript also has automatic semicolon insertion, or ASI, which can add missing semicolons at certain line breaks. ASI is like autocorrect for periods: usually helpful, occasionally wrong for what you meant.
If you forget a period in a text message, autocorrect may add one. Usually that helps. Sometimes it changes the meaning. ASI is the code version: it follows rules, not your intention.
- In real life: A period ends a sentence
- In JavaScript: A semicolon ends many statements
- In real life: Autocorrect guesses missing punctuation
- In JavaScript: ASI inserts semicolons in allowed places
- In real life: Autocorrect can guess wrong
- In JavaScript: ASI can join a line starting with
[or endreturnearly
Where the analogy stops: Semicolons are not required after every JavaScript construct. Blocks after if and function declarations do not need them. The analogy is about statement endings, not all punctuation.
First pitfall: a line that begins with [, (, or a template backtick can continue the previous statement. Toggle the semicolon below. In Chrome and Node, the broken version throws TypeError: Cannot read properties of undefined (reading 'forEach'). Other engines may word the message differently, so tests assert the error name and treat the V8 message as an example.
Toggle the semicolon on line 1. Predict whether line 2 starts fresh or gets glued to line 1.
script
[1, 2].forEach((n) => console.log(n));Second pitfall: return followed by a line break. The displayed function below really returns undefined, because ASI ends the return statement before the object-looking block.
function makeCard() { return { title: "JavaScript" };}console.log(makeCard());Put the object on the same line as return, or wrap the expression intentionally.
The displayed function returns undefined. ASI inserts a semicolon immediately after return, before the object-looking block.
Write semicolons at statement ends while you are learning. Never put the value for return on the next line. If a line starts with (, [, or a template backtick, make sure the previous statement has clearly ended.
Where you'll use this
This topic appears everywhere. Function bodies are statement lists. Conditions are expressions. if, loops, and functions use blocks. Comments explain non-obvious decisions. Semicolons and formatting make reviews calmer because readers do not have to guess where a statement ends.
// 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. Lines 2 through 5 are a block. Line 8 adds a semicolon before a line that starts with [. The comments explain intent, not the obvious fact that console.log prints.
Up next, strict mode begins with "use strict";. That line is a directive: a special expression statement at the top of a script or function. You do not need the full strict-mode rules yet; just notice that the structure matters.
Common misconceptions
“Expressions are only math.”
Strings, comparisons, property reads, and function calls are expressions too because they produce values.
“Semicolons are always optional.”
ASI often helps, but missing semicolons before [, (, or a template backtick can join lines in surprising ways.
“Braces always mean object.”
At statement start, braces begin a block. Use parentheses when you need an object expression.
“Indentation creates blocks.”
JavaScript uses braces, not indentation, to group statements. Indentation is for humans.
“Comments can be nested if they look balanced.”
Block comments end at the first */. Nested /* ... */ comments break.
| Looks like | Actually | Safe habit |
|---|---|---|
{ a: 1 } | A block with a label at statement start | Write ({ a: 1 }) for an object expression |
return then newline then object | Return undefined, then unreachable block | Keep the return value on the same line |
if (ready); { ... } | if controls the empty statement | Delete the stray semicolon |
// inside a string | Ordinary text | Only // outside strings starts a comment |
Practice: read the structure
6 EXERCISESWhich one is an expression: if (x) {} or x > 2?
x > 2 is the expression because it produces a boolean value. if (x) {} is a statement that decides whether another statement runs.
Predict exactly what the program prints.
function label() {
return
{
text: "done"
};
}
console.log(label());The function prints undefined. The object-looking braces are not returned because return ended on line 2.
The broken version throws in V8. Add one character so it prints the array items.
const a = 1
[1, 2].forEach((n) => console.log(n));const a = 1;
[1, 2].forEach((n) => console.log(n));The semicolon ends the declaration. Then the array line runs separately and prints 1 and 2.
Which character makes this program log even when isReady is false?
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. Removing it makes the block the statement controlled by if.
What should wrap { a: 1 } so JavaScript treats it as an object expression?
console.log(({ a: 1 }).a);Parentheses make the braces an object expression. Then .a reads the property and prints 1.
Pick a small piece of your own code and add one comment that explains why it exists. Avoid repeating the code in English.
// Keep the first item as a featured card for the layout.
const featured = items[0];The comment explains the reason for choosing the first item. JavaScript ignores it, but another human now knows why the code exists.
Quiz: check your understanding
8 QUESTIONSAnswer before expanding explanations. Every code answer is based on real JavaScript behavior.
Question 1 of 8Which description best matches 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
;by itself?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 8What does the return-newline function print?
Read the code, then predictfunction makeCard() { return { title: "JavaScript" }; } console.log(makeCard());Choose an answer to see the explanation.
Question 7 of 8Which comment form can span more than one line?
Choose an answer to see the explanation.
Question 8 of 8Which whitespace choice can change meaning?
Choose an answer to see the explanation.
Key takeaways
- Statements are complete instructions; expressions produce values.
- Expression statements are useful when an expression has a side effect, like
console.log. - A block statement groups statements and creates block scope for
letandconst. - At statement start, braces start a block. Use parentheses for object expressions when needed.
- ASI helps, but be careful after
returnand before lines starting with(,[, or a template backtick. - Comments are for humans; whitespace mostly helps readers, and formatting tools keep it consistent.
Remember the one-liner.
JavaScript reads a script as statements; expressions provide values inside them; punctuation and formatting tell readers and the parser where each idea ends.
If you want to revisit the big picture, return to Why JavaScript?. Up next: Strict mode.
Comments, whitespace, and formatting
Comments are sticky notes for humans. JavaScript removes them before running the code. Use comments to explain why something is done, or to leave a short note for future maintainers. Do not use a comment to repeat code that is already obvious.
A useful comment helps a person understand intent. It does not make the computer do anything new.
Where the analogy stops: Comments can be read by tools, especially JSDoc-style comments. They are ignored by the JavaScript runtime, but not always by editors or documentation generators.
//starts a single-line comment./* ... */is a block comment. It can span lines, but it does not nest./** ... */is JSDoc-style: still a block comment, but tools can use it.//inside quotes is part of a string, not a comment.Whitespace is like spacing in a sentence. Spaces, tabs, and most line breaks help readers but do not change meaning:
2+2and2 + 2are the same expression. Formatting tools such as Prettier keep spacing consistent. The exceptions you have met are line breaks nearreturnand before lines that can attach to the previous statement.