JavaScript Code Is a Sequence of Statements
A JavaScript program is a list of statements — instructions the engine runs top to bottom. Declaring a variable is a statement. Calling a function is a statement. An if or a for block is a statement. Statements are separated from each other by semicolons.
Three statements, three semicolons. The engine runs the first, then the second, then the third. Simple enough.
Whitespace and indentation don't mean anything to the parser. You could put all three on one line with semicolons between them and it would run identically. We indent for human readers, not for the engine.
Blocks Group Statements Together
Curly braces { } create a block — a group of statements the engine treats as a unit. You'll see blocks everywhere: function bodies, if branches, loop bodies.
The two console.log calls inside the braces are the body of the if. Notice there's no semicolon after the closing } — blocks aren't statements that need terminating. The if statement as a whole ends when the block ends.
This catches people who come from languages where every } wants a ; after it. In JavaScript, a standalone block or control-flow block does not.
Expressions vs. Statements
One distinction worth getting clear early: expressions produce a value, statements do something.
2 + 3is an expression. It evaluates to5.let x = 2 + 3;is a statement. It declares a variable and assigns the result of an expression to it.console.log("hi")is an expression (a function call returnsundefined), but written on its own line with a semicolon it becomes an expression statement.
Most of the time you don't have to think about this. It matters when you meet arrow functions, ternaries, and places where JavaScript wants an expression but you tried to give it a statement (or the other way around).
The Semicolon Question
Here's the honest answer: JavaScript has a feature called Automatic Semicolon Insertion (ASI) that inserts missing semicolons for you at most line breaks. That means code like this runs fine:
No semicolons, no error. ASI looks at each line break and asks, "could the next token continue the current statement?" If not, it inserts a semicolon.
Because of ASI, two legitimate styles exist in the wild:
- Semicolons always. Most codebases, most tutorials, most style guides.
- No semicolons. Used by some modern projects (Standard style, some React codebases). Relies on ASI plus a couple of defensive tricks.
Both work. Neither is "wrong." What is wrong is inconsistency — mixing styles inside one file makes bugs harder to spot.
Where ASI Bites You
ASI does the right thing ~99% of the time. The remaining 1% is lines that start with a token that could continue the previous line. The troublemakers are [, (, `, +, -, and /.
Look at this:
You'd expect x and y to swap. Instead, ASI doesn't insert a semicolon before [x, y] because 10[x, y] is syntactically valid (indexing into the number 10). The parser reads line 2 and line 3 as one big expression, and you get a runtime error or garbage output.
The fix is either a semicolon at the end of line 2:
Or, if you're writing in no-semicolon style, a leading semicolon on the risky line:
That leading ; is the defensive trick no-semicolon codebases use. It looks odd until you know why it's there.
The return Trap
One ASI case is worth memorising because it produces silent bugs. If you put a line break right after return, ASI inserts a semicolon there, and the function returns undefined:
The author meant to return an object. ASI saw return at the end of a line and terminated the statement on the spot. The object literal became unreachable code.
The fix is to start the value on the same line as return:
The same rule applies to throw, break, continue, and yield — don't put a line break between the keyword and its value.
A Simple Rule That Works
If you're starting out, the easiest path is:
- Write semicolons explicitly at the end of every statement.
- Don't put them after block-closing
}forif,for,while, function declarations, or class bodies. - Do put them after
}for an object literal or a function expression assigned to a variable:const f = function() {};. - Use a formatter (Prettier, ESLint with a style rule) and stop thinking about it. The formatter enforces whatever your team decided.
This rule isn't universal law — it's the convention you'll see in the majority of JavaScript you read. Stick with it until you have a reason not to.
Case Sensitivity and Identifiers
Two small rules that live here too:
- JavaScript is case-sensitive.
userName,username, andUserNameare three different identifiers. - Identifiers can contain letters, digits,
_, and$, but can't start with a digit. They can't be reserved words likeclass,return, orfunction.
The $ is legal but usually reserved by convention for library-specific things (jQuery used it historically, some template systems still do). You rarely pick it yourself.
Next: Strict Mode
Modern JavaScript quietly runs in a tighter variant of the language called strict mode, which turns a handful of sloppy behaviors into real errors. ES modules and class bodies are strict by default, but it's worth knowing what that actually changes — that's the next page.
Frequently Asked Questions
Do you need semicolons in JavaScript?
Technically no — JavaScript has Automatic Semicolon Insertion (ASI), which adds them for you at most line breaks. In practice, most teams still write them explicitly because ASI has a handful of edge cases (lines starting with [, (, `, +, -, /) where it does the wrong thing. Pick a style and let a formatter like Prettier enforce it.
What is automatic semicolon insertion in JavaScript?
ASI is the rule that lets JavaScript insert missing semicolons at the end of a line when the next token couldn't continue the current statement. It's why let x = 1 works without a semicolon. It fails when a line happens to start with something that can continue the previous line — like [ or ( — and JavaScript quietly glues the two lines together.
What's the basic syntax of a JavaScript statement?
A statement is an instruction — a variable declaration, a function call, an if block, a loop. Statements are separated by semicolons (explicit or inserted). Blocks of statements go inside { }. Whitespace and indentation are ignored by the parser, so formatting is for humans, not the engine.