JavaScript Statements

5 minute read

A statement is a single instruction for the JavaScript engine to execute. Every program you write — from a one-liner to a million-line app — is just a sequence of statements running top to bottom. Get the rules right and your code is predictable; get them wrong and the engine silently inserts semicolons where you didn’t want them.

What Counts as a Statement?

let name = "Ada";          // declaration statement
name = name.toUpperCase(); // assignment statement
console.log(name);         // expression statement
if (name) { /* ... */ }    // control-flow statement
return name;               // jump statement

Almost everything you write is a statement. The engine executes them one at a time, in order.

Category Examples
Declarations let, const, function, class
Assignments / expressions x = 5, myFn(), a + b (when used alone)
Control flow if, else, switch, for, while
Jumps return, break, continue, throw
Blocks { ... } grouping zero or more statements

Statements vs Expressions

This distinction trips up most beginners. An expression produces a value. A statement performs an action. Some statements contain expressions; some expressions are statements on their own.

2 + 3              // expression → 5
"hello"            // expression → "hello"
isLoggedIn         // expression → boolean
isLoggedIn = true  // expression (assignment returns the value) AND a statement
let x = 5;         // statement — declarations are not expressions
if (x) {}          // statement — control flow is not an expression
  Expression Statement
Produces a value ✅ ❌ (most don’t)
Can be used inside () ✅ ❌
Can stand alone with ; ✅ (becomes expression statement) ✅
Examples 1 + 1, fn(), a && b if, for, return, let x = 1
// Expression — can go anywhere a value is needed
const total = (2 + 3) * 4;          // (2 + 3) is an expression
console.log(isLoggedIn ? "in" : "out"); // ternary is an expression

// Statement — cannot go inside ()
// const x = (if (true) 1 else 2);   // ❌ SyntaxError

Semicolons — Are They Required?

Officially: every statement ends with a semicolon ;. In practice: JavaScript has a feature called Automatic Semicolon Insertion (ASI) that adds them for you in most cases.

// Both are valid
let a = 1;
let b = 2;

let a = 1
let b = 2

But ASI has surprising edge cases:

// ❌ ASI inserts a semicolon after `return` — function returns undefined!
function getUser() {
  return
    {
      name: "Ada"
    }
}
console.log(getUser()); // undefined

// ✅ Keep the opening brace on the same line
function getUser() {
  return {
    name: "Ada"
  };
}
// ❌ Two adjacent lines starting with [ or ( can merge into one statement
const a = 1
[1, 2, 3].forEach(console.log)  // parsed as: 1[1,2,3].forEach(...)  → TypeError

// ✅ Either add semicolons, or prefix the trap-line with one
const a = 1;
[1, 2, 3].forEach(console.log);

Tip: Pick a style and stick with it. The two dominant conventions are: “always semicolons” (Prettier default) and “no semicolons, ASI” (StandardJS). Both work — what matters is consistency, enforced by a linter or formatter.

Code Blocks — { ... }

A pair of curly braces groups statements into a block. Blocks are how you tell if, for, while, and friends what to run.

if (loggedIn) {
  console.log("Welcome back");
  showDashboard();
  trackEvent("login");
}

A block can also stand alone, creating a new scope (covered in chapter 30):

{
  const secret = 42;
  console.log(secret); // 42
}
console.log(secret); // ❌ ReferenceError

Whitespace and Line Breaks

JavaScript ignores almost all whitespace. Spaces, tabs, and newlines are interchangeable for formatting — except where ASI cares.

// All equivalent
let x=1+2;
let x = 1 + 2;
let x   =   1   +   2 ;

let result = 1
           + 2
           + 3
           + 4;

That said, your team and tools care about whitespace deeply. Use a formatter (Prettier) and never argue about it again.

One Statement Per Line — A Convention

You can put many statements on one line by separating them with semicolons. You shouldn’t:

// ❌ Hard to read, hard to debug
let a = 1; let b = 2; if (a < b) { console.log("smaller"); }

// ✅ One statement per line
let a = 1;
let b = 2;
if (a < b) {
  console.log("smaller");
}
Style Readability Debuggability
One statement per line ✅ Clear ✅ Stack traces map cleanly
Multiple per line ❌ Cramped ❌ Hard to set breakpoints

Empty Statements

A single ; is a legal empty statement — it does nothing. Useful in loops where the work is done in the header:

// Read characters until EOF — body is just an empty statement
let ch;
while ((ch = readChar()) !== null);  // semicolon = empty body

// But this is a common bug source:
if (loggedIn);       // ❌ stray semicolon — the if has NO body
  showDashboard();   // runs unconditionally!

Warning: Beware accidental ; right after if, for, or while. The statement is “complete” with no body, and the next line runs always.

Statement Execution Order

Statements run top to bottom, one at a time, on the single main thread.

┌─────────────────────────────┐
│ let x = 5;          (1)     │
│ console.log(x);     (2)     │   ┐
│ if (x > 0) {                │   │
│   console.log("pos"); (3)   │   │ executed in order
│ }                           │   │ 1 → 2 → 3 → 4
│ x = 0;              (4)     │   ┘
└─────────────────────────────┘

Asynchronous code (chapters 38–41) breaks this only at well-defined points (await, callbacks, promises). Synchronous statements always run in order.

Worked Example

// 1. Declarations
const PI = 3.14159;
let radius = 5;

// 2. Expression statement (call has a side effect)
console.log("Calculating...");

// 3. Assignment
const area = PI * radius ** 2;

// 4. Control flow + block
if (area > 50) {
  console.log(`Large circle: ${area.toFixed(2)}`);
} else {
  console.log(`Small circle: ${area.toFixed(2)}`);
}

// 5. Jump (in a function context)
function describe(r) {
  if (r < 0) return "invalid";
  return `radius ${r}`;
}

console.log(describe(radius));
// Output:
// Calculating...
// Large circle: 78.54
// radius 5

Every line is a statement. The engine reads them top to bottom and executes each one in sequence.

Best Practices Checklist

  • ✅ One statement per line
  • ✅ Use a formatter (Prettier) — let it handle semicolons
  • ✅ Always use {} blocks with if, for, while — even for one statement
  • ✅ Keep return and its value on the same line
  • ❌ Don’t rely on ASI in edge cases — write defensively
  • ❌ Don’t put a ; immediately after if, for, or while

What’s Next?

Statements give you the what — syntax rules tell you the how. Next we’ll cover the building blocks of valid code: keywords, identifiers, literals, operators, and the conventions that make code readable.

← Previous: JS Output Next: JS Syntax →

Updated: