The rules JavaScript uses to read your code — semicolons, comments, blocks, and the ASI trap.
What it is, in plain English: Syntax is the grammar of a programming language — the rules it uses to understand what you wrote. In JavaScript, statements end with a semicolon (optional but recommended), blocks of code live inside curly braces { }, and comments let you leave notes. Unlike Python, indentation doesn't matter — JavaScript uses braces to group code.
How JavaScript reads your code
Before JavaScript runs your program, it reads it — like a reader scanning a page.
It needs your code to follow certain rules so it knows where one instruction ends and the next begins.
These rules are called syntax.
Statements
A statement is one complete instruction. Think of it like a sentence.
In English, sentences end with a full stop. In JavaScript, statements end with a semicolon.
console.log("Hello"); // one statement
let x = 5; // another statement
x = x + 1; // another statement
JavaScript can usually figure out where statements end even without semicolons
(this is called ASI — see the Intermediate tab). But beginners should always write semicolons
to avoid subtle bugs. Every statement in this course has one.
Comments
Comments are notes you leave in code. JavaScript ignores them completely — they're for humans.
// This is a single-line comment
// Everything after // on this line is ignored
let price = 9.99; // you can put a comment after code too
/*
This is a multi-line comment.
Useful for longer explanations
or temporarily disabling a block of code.
*/
let tax = price * 0.1; /* also works inline */
In this course, every code example has comments explaining what each line does and why.
Write comments like this in your own code — your future self will thank you.
Blocks: grouping code with curly braces
A block is a group of statements wrapped in curly braces { }.
This is how JavaScript knows which statements belong together — inside an if, a loop, a function.
// An if statement uses a block:
if (temperature > 30) {
// everything inside these braces runs only if the condition is true
console.log("It's hot!");
console.log("Drink water.");
}
// A function uses a block:
function greet() {
// everything in here runs when greet() is called
let message = "Hello!";
console.log(message);
}
Key difference from Python: Python uses indentation to group code.
JavaScript uses curly braces. Indentation in JavaScript is just style — it doesn't
affect what the code does. The braces do.
Case sensitivity
JavaScript is case-sensitive. myName, MyName, and
MYNAME are three completely different things. A common beginner mistake:
let myName = "Alice";
console.log(myName); // works ✓
console.log(MyName); // ReferenceError: MyName is not defined ✗
Whitespace and indentation
JavaScript ignores extra whitespace. These two blocks do exactly the same thing:
// Well-formatted (do this):
if (x > 0) {
console.log("positive");
}
// Terrible but valid (don't do this):
if(x>0){console.log("positive");}
Always use consistent indentation — 2 spaces is the JavaScript convention (Python uses 4).
Not because JavaScript cares, but because other humans need to read your code.
Naming things: identifiers
Names for variables, functions, and other things are called identifiers.
The rules:
Must start with a letter, underscore _, or dollar sign $
Can contain letters, numbers, _, $ (but not start with a number)
Cannot be a reserved word like let, if, function
JavaScript convention: camelCase for variables and functions (myVariable, getUserName)
let firstName = "Alice"; // ✓ camelCase (JS convention)
let _private = 42; // ✓ underscore prefix (used for "private" by convention)
let $price = 9.99; // ✓ dollar sign (jQuery used this heavily)
let 2fast = true; // ✗ SyntaxError: cannot start with a number
Try It Yourself
ASI, strict mode, and expressions vs statements
Automatic Semicolon Insertion (ASI) — the rule and the traps
JavaScript's parser automatically inserts semicolons in certain situations — this is
called ASI (Automatic Semicolon Insertion). The rule is complex, but the
practical summary: JS inserts a semicolon when the next token can't continue the current statement.
Most of the time this works fine. But there are three classic ASI traps:
// TRAP 1: return on its own line
function getObject() {
return // ← ASI inserts ; here — function returns undefined!
{
name: "Alice"
};
}
// Fix: put the { on the same line as return:
function getObjectFixed() {
return { // ← no ASI here — { continues the statement
name: "Alice"
};
}
// TRAP 2: line starting with [ or (
let a = 1
let b = 2
[a, b] = [b, a] // ← parsed as: let b = 2[a, b] = [b, a] → TypeError
// Fix: add semicolons, OR put ; before the [
;[a, b] = [b, a] // defensive semicolon
// TRAP 3: ++ and -- on a new line
let x = 5
x
++ // ← parsed as: x; ++; (two statements, ++ with nothing to increment)
// Fix: keep x++ on one line
The solution: always write semicolons. The community is split (some style
guides omit them relying on ASI), but explicit semicolons eliminate the traps entirely.
Strict mode
Adding "use strict"; at the top of a file (or function) opts into strict mode —
a stricter variant of JavaScript that catches more errors:
"use strict";
// Strict mode prevents these silent errors:
x = 10; // ✗ ReferenceError (without strict: silently creates global)
delete Object.prototype; // ✗ TypeError (without strict: silently fails)
let arguments = 5; // ✗ SyntaxError (arguments is reserved)
function f(a, a) {} // ✗ SyntaxError (duplicate params)
ES Modules are always in strict mode automatically. In non-module scripts, add
"use strict" at the top. Always use it.
Expressions vs statements
An expression produces a value. A statement performs an action.
// Expressions (produce a value):
5 + 3 // 8
"hello".length // 5
x > 0 // true or false
greet() // whatever greet() returns
// Statements (perform an action):
let x = 5; // declaration statement
if (x > 0) { ... } // if statement
for (let i = 0; ...) // for statement
return value; // return statement
The distinction matters because some places in JS require expressions (the right side of an
assignment, inside a function call's arguments, inside template literals) while others
require statements (the body of an if, the branches of a switch).
The comma operator
The comma operator evaluates both operands and returns the value of the last one.
Almost never used intentionally, but shows up in minified code:
let x = (1 + 2, 3 + 4); // x = 7 (last expression)
// Useful only in for loop headers:
for (let i = 0, j = 10; i < j; i++, j--) { ... }
Parsing, the AST, and language grammar
How the parser builds an AST
JavaScript source code is parsed in two phases: lexing (tokenising the character
stream into tokens: keywords, identifiers, literals, operators, punctuators) and parsing
(consuming the token stream and producing an Abstract Syntax Tree).
The ECMAScript grammar is a context-free grammar written in a modified BNF notation. You can
read it at tc39.es/ecma262/#sec-ecmascript-language-statements-and-declarations.
The grammar distinguishes between goals: Script (classic scripts) vs
Module (ES modules) — the same source text can parse differently depending on the goal.
ASI — the formal rule (ECMA-262 §12.10)
The spec defines ASI precisely. A semicolon is inserted when:
The next token is not allowed by the grammar, and at least one line terminator precedes it, OR
The end of input is reached and the grammar cannot accept the stream, OR
The token is a "restricted production" — return, throw, break,
continue, ++, -- — where a line terminator before the
next token triggers insertion regardless of what follows
The "restricted production" rule is why return
{} inserts a semicolon after
return: return is a restricted production, the line terminator triggers ASI.
Directive prologues and "use strict"
A "directive prologue" is a sequence of ExpressionStatements at the start of a function or
script where each expression is a string literal. "use strict" is the only
standardised directive (ECMA-262 §11.2.1). Engines may support others ("use asm"
for asm.js), but they're not standardised. In strict mode, the following are syntax errors that
are silent in sloppy mode: with statement, duplicate property names in object literals (ES5 only,
allowed in ES2015+), delete on a non-configurable property, etc.
Parsing ambiguity: expression vs statement context
The grammar has two ambiguities that parsers handle specially:
{ at statement position: could be a block or an object literal.
Parsers always treat it as a block. This is why eval("{}") returns
undefined (empty block) not an empty object.
function at statement position: could be a function declaration
or a function expression. It's always a declaration — which is why it's hoisted.
To force expression context: wrap in parens: (function() {})() — the IIFE pattern.