In the previous lesson you wrote your first program: a handful of lines that printed the summary of a Taller Nómada task. It worked, but you copied the shape without knowing the rules. Now you are going to learn them. Syntax is the grammar of the language: which symbols exist, how instructions are separated, what names you can use and how a program is read. Mastering it is what turns errors from "I have no idea what is going on" into "ah, there is a semicolon missing on line 12". It is the foundation absolutely everything else rests on.
Contents
- Statements and semicolons
- Automatic Semicolon Insertion (ASI)
- Blocks with braces
{} - Case sensitivity
- Rules and conventions for names
- Reserved words
- Whitespace, indentation and style
- Expressions versus statements
- Literals
strict mode- How a program is read from top to bottom
- Common Mistakes and Tips
- Exercises
- Conclusion
- Statements and semicolons
A program is a sequence of statements (or instructions): complete orders that the engine executes one after another. Each statement ends with a semicolon (;).
const title = 'Redesign the multipurpose room';
const assignee = 'Iván';
console.log(title, assignee);There are three statements there: two declarations and one function call. They run in order, from top to bottom.
Technically you can put several on the same line if you separate them with ;, but do not do it: it reads far worse.
// Valid but unreadable: avoid it
const priority = 'high'; const hours = 12; console.log(priority, hours);1.1 Statements that do not take a semicolon
There are important exceptions. Code blocks do not take a semicolon after the closing brace:
// Correct: there is no semicolon after the closing brace
if (priority === 'high') {
console.log('Urgent task');
}
// A function declaration does not take one either
function showTask() {
console.log('Taller Nómada task');
}However, when a function is assigned to a variable, it does take a semicolon, because the complete statement is the assignment:
const showTask = function () {
console.log('Taller Nómada task');
}; // ← this semicolon closes the assignmentThe mental rule is simple: the semicolon closes a statement, not a block.
- Automatic Semicolon Insertion (ASI)
Here comes one of the most debated quirks of JavaScript. The language has a mechanism called ASI (Automatic Semicolon Insertion): if a line ends and the engine decides the statement is complete, it inserts a semicolon on its own.
That is why this code runs without errors:
So do you actually need to write them? The problem is that ASI gets it right almost always, but not always, and when it fails the resulting error is baffling.
2.1 The dangerous case: return
// Trap! ASI inserts a semicolon after return
function getSummary() {
return
{
title: 'Set up the screen-printing workshop'
};
}
console.log(getSummary()); // undefinedThe engine reads return, sees the end of the line, decides the statement is complete and inserts ;. The object on the following lines is left orphaned and the function returns undefined. The fix is to put the opening brace on the same line as return.
2.2 The dangerous case: lines starting with ( or [
const ivanHours = 12
const luciaHours = 8
// This line starts with a parenthesis
;(function () {
console.log('Independent block');
})();Without that leading semicolon, the engine would read 8(...) as a function call on the number 8, and would throw a TypeError. The same problem happens with lines that start with [.
2.3 The recommendation
| Style | Advantages | Drawbacks |
|---|---|---|
Always writing ; |
Predictable, no surprises, the majority practice in the industry | One extra character per line |
| Omitting them | Code that looks slightly cleaner | Requires knowing and remembering the exceptions |
In this course we will always write the semicolon. It is the safe option while you are learning, and the most common one in professional teams. If one day you work on a project that omits them, a formatting tool will take care of it automatically.
- Blocks with braces
{}
{}A block groups several statements so that they are treated as a unit. It is delimited with braces.
Braces appear in conditionals, loops, functions and classes. Two observations for beginners:
First: if an if has a single statement, the braces are optional. But omitting them is a classic source of bugs:
// Classic trap: only the first line depends on the if
if (priority === 'high')
console.log('Notify the team');
console.log('This line runs ALWAYS');The indentation suggests that both lines depend on the if, but only the first one does. Always use braces, even for a single line.
Second: blocks create scope for let and const. A variable declared inside a block does not exist outside it. It is a central idea that you will see in detail in Variables and Data Types and in depth in Scope and Closures.
{
const note = 'Only visible inside the block';
console.log(note); // works
}
// console.log(note); // ReferenceError: note is not defined
- Case sensitivity
JavaScript distinguishes uppercase from lowercase. No exceptions and no warnings.
const estimatedHours = 12;
console.log(estimatedHours); // 12
// console.log(EstimatedHours); // ReferenceError
// console.log(estimatedhours); // ReferenceErrorThese four spellings are four different identifiers: task, Task, TASK, tAsK.
This also affects keywords and the language's own functions:
| Correct | Incorrect | Resulting error |
|---|---|---|
console.log() |
Console.log() |
ReferenceError: Console is not defined |
const |
Const |
SyntaxError |
if |
If |
ReferenceError: If is not defined |
Math.round() |
math.round() |
ReferenceError: math is not defined |
Notice something revealing: console is lowercase but Math is capitalized. There is no logic that explains it; it is the language's history. When in doubt, check the documentation.
- Rules and conventions for names
An identifier is the name you give a variable, function or class. There are rules (mandatory) and conventions (industry agreements).
5.1 Mandatory rules
A valid identifier:
- Starts with a letter, an underscore (
_) or a dollar sign ($). - May then contain letters, digits,
_and$. - Cannot start with a digit.
- Cannot contain spaces or hyphens (
-). - Cannot be a reserved word.
// Valid
const title = 'Set up the workshop';
const hours2026 = 40;
const _internal = true;
const $element = null;
// Invalid
// const 2hours = 10; // SyntaxError: starts with a digit
// const total-hours = 10; // SyntaxError: the hyphen is the subtraction operator
// const const = 10; // SyntaxError: reserved wordTechnically JavaScript accepts accented and non-ASCII characters (const añoInicio = 2026; works), but do not do it: it complicates collaboration, causes encoding problems and is not industry practice. Keep identifiers in plain ASCII English.
5.2 Naming conventions
| Convention | Appearance | Used for | Example in Nómada Tasks |
|---|---|---|---|
| camelCase | First word lowercase, following words capitalized | Variables and functions | estimatedHours, dueDate, calculateWorkload |
| PascalCase | Every word capitalized | Classes and constructors | Task, TaskManager |
| UPPER_SNAKE_CASE | All uppercase, words separated by _ |
Fixed global constants | VALID_PRIORITIES, MAX_WEEKLY_HOURS |
| _leadingUnderscore | Starts with _ |
An old convention for "internal use" | _internalCache |
Applied to the project:
// Global configuration constant: UPPER_SNAKE_CASE
const MAX_WEEKLY_HOURS = 40;
// Regular variables: camelCase
const taskAssignee = 'Marta';
const estimatedHours = 6;
const dueDate = '2026-10-15';5.3 Names that make sense
Conventions tell you how to write; judgment tells you what to write.
| Bad name | Good name | Why |
|---|---|---|
x |
estimatedHours |
x says nothing |
d |
dueDate |
Single-letter abbreviations are forgotten |
data |
pendingTasks |
"Data" describes everything and nothing |
flag |
isCompleted |
Booleans read better as a statement of fact |
tmp2 |
remainingHours |
Numbered names hide the meaning |
Practical rule: if you need a comment to explain what a variable holds, change its name.
- Reserved words
These are terms with their own meaning in the language; you cannot use them as identifiers.
| Category | Words |
|---|---|
| Declaration | var, let, const, function, class |
| Flow control | if, else, switch, case, default, for, while, do, break, continue, return |
| Errors | try, catch, finally, throw |
| Objects | new, this, super, delete, in, instanceof, typeof, void |
| Modules | import, export, from, as |
| Asynchrony | async, await, yield |
| Values | true, false, null |
| Reserved for the future | enum, implements, interface, package, private, protected, public, static |
// const class = 'design'; // SyntaxError
// const new = 'task'; // SyntaxError
// Correct alternatives
const category = 'design';
const newTask = 'task';Two curious details: undefined is not a reserved word (it is a global variable, although you should never reassign it), and await is only reserved inside async functions and in modules.
- Whitespace, indentation and style
As far as the engine is concerned, whitespace and line breaks are irrelevant (except inside strings). These two versions are identical to JavaScript:
Identical for the machine, but radically different for a human. And code is read many more times than it is written.
Common conventions:
| Aspect | Convention | Example |
|---|---|---|
| Indentation | 2 spaces per level | console.log(x); |
| Spaces around operators | Yes | const total = a + b; |
| Space after commas | Yes | console.log(a, b, c); |
| Opening brace | On the same line | if (x) { |
Space after if, for, while |
Yes | if (priority === 'high') { |
| Space before the parenthesis when calling | No | calculateWorkload(tasks) |
| Line length | Around 80-100 characters | — |
Do not memorize this table: in Module 8 you will configure tools that apply the formatting automatically on save. What matters right now is that you pick a style and stick to it.
- Expressions versus statements
This distinction sounds theoretical and turns out to be tremendously practical.
- An expression is a piece of code that produces a value.
- A statement is a complete order that does something.
The definitive test: can I put this where a value is expected? If yes, it is an expression.
// Expressions: each one produces a value
12 // the number 12
12 + 8 // 20
'Marta' // the text 'Marta'
estimatedHours > 10 // true or false
'high' === 'high' // true
calculateWorkload('Iván') // whatever the function returns// Statements: they are orders, not values
const assignee = 'Lucía';
if (hours > 8) { console.log('Long day'); }
for (let i = 0; i < 3; i++) { console.log(i); }Expressions nest inside statements:
Why does it matter? Because it explains what can be written where. An if is a statement, so you cannot assign it to a variable:
But the ternary operator is an expression, and that is why this works:
You will study that operator in Basic Operators. Hold on to the idea: expressions are worth something; statements give orders.
- Literals
A literal is a value written directly in the code, exactly as it is.
| Literal type | Example | Description |
|---|---|---|
| Numeric | 12, 3.5, 1_000_000 |
Numbers written directly |
| String | 'Marta', "high" |
Text between quotes |
| Template | `Task for ${assignee}` |
Text between backticks, supports interpolation |
| Boolean | true, false |
The two logical values |
| Null | null |
The intentional absence of a value |
| Object | { title: 'Review', hours: 3 } |
An object written directly |
| Array | ['design', 'space'] |
A list written directly |
| Regular expression | /^\d{4}-\d{2}-\d{2}$/ |
A text pattern |
// Different literals describing a Taller Nómada task
const id = 1; // numeric
const title = 'Redesign the room'; // string
const isDone = false; // boolean
const tags = ['design', 'space']; // array
const assignedTo = null; // nullThe underscore as a thousands separator (1_000_000) is a modern convenience: the engine ignores it and the number becomes far more readable for you.
strict mode
strict modeStrict mode turns on a more rigorous version of JavaScript: it turns some silent behaviors into errors and bans problematic legacy syntax.
You enable it by writing 'use strict'; as the first line of a file or of a function:
10.1 What changes
| Without strict mode | With strict mode |
|---|---|
x = 5; without declaring silently creates a global variable |
ReferenceError: x is not defined |
| Assigning to something read-only fails silently | Throws TypeError |
this inside a standalone function is the global object |
this is undefined |
| Duplicate parameters in functions are allowed | SyntaxError |
| Future reserved words usable as names | Forbidden |
The first case is the one that causes the most trouble:
'use strict';
function logTask() {
totalHours = 12; // ReferenceError: totalHours is not defined
}
logTask();Without strict mode, that line would create a global variable without any warning. It is a typo that can take weeks to show itself. With strict mode, the error appears instantly.
10.2 When you actually need to write it
Good news: less and less often. Strict mode is enabled automatically in two very common contexts:
- Inside JavaScript modules (files loaded with
<script type="module">or withimport/export). They are covered in Modules: Import and Export. - Inside the body of classes.
So the practical rule is: write 'use strict'; at the top of classic script files, and do not worry about it when you are working with modules or classes.
One detail: the directive must be literally the first statement (comments above it do not count). If you put it further down, it is ignored without warning.
- How a program is read from top to bottom
A JavaScript engine executes statements in the order they are written, top to bottom and left to right. Follow this program in your head before you read the result:
'use strict';
console.log('1. The program starts'); // A
const assignee = 'Marta'; // B
console.log('2. Assignee:', assignee); // C
const mondayHours = 3; // D
const tuesdayHours = 5; // E
const totalHours = mondayHours + tuesdayHours; // F
console.log('3. Total hours:', totalHours); // G
console.log('4. The program ends'); // HOutput:
A detail about line F: first the expressions are evaluated (mondayHours is 3, tuesdayHours is 5, the sum is 8) and only afterwards is the result assigned. Always in that order: the right-hand side is computed first, then stored on the left.
flowchart TD
A["Line 1: initial message"] --> B["Line 2: store 'Marta'"]
B --> C["Line 3: print the assignee"]
C --> D["Lines 4-5: store 3 and 5"]
D --> E["Line 6: evaluate 3 + 5 → 8<br/>and assign to totalHours"]
E --> F["Lines 7-8: print the results"]
A practical consequence: you cannot use something before creating it. This fails:
console.log(assignee); // ReferenceError: Cannot access 'assignee' before initialization
const assignee = 'Lucía';There is a mechanism called hoisting that does allow function declarations to be used before they appear in the code, and that explains the specific wording of that error. It is a topic with enough substance to deserve its own lesson: Hoisting and the Execution Context. For now, the safe rule is: declare before you use.
Common Mistakes and Tips
Common mistakes
- Putting a semicolon after the closing brace of an
if,fororfunction. It is not a serious error, but it is incorrect and gives a beginner away. - Omitting the braces in a single-line
if. The indentation lies; the engine does not. - Getting the capitalization wrong.
Console, a lowercasemath,getElementByIDinstead ofgetElementById. They cause bafflingReferenceErrororTypeErrormessages. - Using hyphens in names.
total-hoursis read astotal - hours, a subtraction. The resulting error does not mention the hyphen at all. - Writing
'use strict';in the middle of the file. It is silently ignored. It has to be the first statement. - Believing that indentation has meaning. In JavaScript it does not (unlike Python): indentation is only for humans. Blocks are defined by braces.
- Single-letter names. They take two seconds to write and cost hours to decipher. Except for the
iof a short loop, use full names.
Tips
- Always write the semicolon while you are learning. It saves you from the ASI exceptions.
- Always use the braces.
- Leave a blank line between logical blocks. The code breathes and reads better.
- Name things in camelCase and in a single language. Mixing
taskTitleandtituloTareain the same file is exhausting. - Format with
Shift + Alt + Fin VS Code. Well-aligned code reveals structural mistakes at a glance. - When you see a
SyntaxError, also look at the line above the one reported. The engine spots the problem where it stops understanding the code, which is usually one line after the missing symbol.
Exercises
Exercise 1: Fix the syntax
The following snippet has six errors of syntax or convention. Find them and write the corrected version.
'use strict'
const 1title = 'Review the workshop inventory';
const estimated-hours = 4;
const ASSIGNEE = 'Lucía';
const class = 'maintenance';
if (estimated-hours > 3)
Console.log('Long task');
console.log('Notify Marta');Exercise 2: Expression or statement?
Classify each snippet as an expression or a statement, and for the expressions state what value it produces:
40const maxHours = 40;estimatedHours * 2console.log('Nómada Tasks')if (status === 'done') { console.log('Completed'); }'high' === 'low'status = 'in-progress'
Exercise 3: Name things correctly
Rewrite these names following JavaScript's rules and conventions, and explain in each case what was wrong:
Estimated Hours(a variable with the hours planned for a task)2assignee(the name of the second person assigned)due-date(the task's deadline)maximum_number_of_hours_per_week(a fixed configuration constant)task(a class that will represent a task)d(a variable holding the due date)
Solutions
Exercise 1
The six errors:
'use strict'without a semicolon (it works thanks to ASI, but it is inconsistent with the course style).1title: an identifier cannot start with a digit.estimated-hours: the hyphen is the subtraction operator; camelCase must be used.class: a reserved word.Console.log:consoleis lowercase.- The
ifwithout braces makes the second line run always, despite the indentation.
Corrected version:
'use strict';
const title = 'Review the workshop inventory';
const estimatedHours = 4;
const assignee = 'Lucía';
const category = 'maintenance';
if (estimatedHours > 3) {
console.log('Long task');
console.log('Notify Marta');
}An additional note: ASSIGNEE in uppercase is not a syntax error, but by convention UPPER_SNAKE_CASE is reserved for global configuration constants, not for specific pieces of data.
Exercise 2
| # | Classification | Value it produces |
|---|---|---|
| 1 | Expression (numeric literal) | 40 |
| 2 | Statement (declaration) | — |
| 3 | Expression (arithmetic) | Twice estimatedHours |
| 4 | Expression (function call) | undefined (it prints, but returns nothing) |
| 5 | Statement (conditional) | — |
| 6 | Expression (comparison) | false |
| 7 | Expression (assignment) | 'in-progress' |
Cases 4 and 7 are the interesting ones. A function call is an expression even if the function returns nothing useful: that is why the console shows undefined below your console.log calls. And an assignment is also an expression whose value is the assigned one; that is why a = b = 5 works, even though writing it is not advisable.
Exercise 3
| Original | Corrected | Problem |
|---|---|---|
Estimated Hours |
estimatedHours |
Spaces are not allowed; camelCase on top of that |
2assignee |
secondAssignee |
Cannot start with a digit |
due-date |
dueDate |
The hyphen is the subtraction operator |
maximum_number_of_hours_per_week |
MAX_WEEKLY_HOURS |
A fixed constant: UPPER_SNAKE_CASE, and more concise |
task |
Task |
Classes use PascalCase |
d |
dueDate |
A single-letter name says nothing |
Conclusion
You now know the grammar of JavaScript. You know what a statement is and why you should always close it with a semicolon despite the existence of ASI; you use {} blocks correctly and you know that they create scope; it is clear to you that the language is case-sensitive; you know the rules for identifiers and the camelCase, PascalCase and UPPER_SNAKE_CASE conventions; you know what the reserved words are; you can tell expressions (which produce a value) from statements (which give an order); you recognize the different literals; you understand what strict mode turns on and where it comes enabled out of the box; and you can mentally follow the top-to-bottom execution of a program.
With this you can read code without the form distracting you. What you are missing is the content: the data. In the next lesson, Variables and Data Types, you will look in depth at how to declare variables with let and const, why var is discouraged, and what types of values exist in JavaScript: strings, numbers, booleans, undefined, null and a few more. By the end of it you will be able to model every field of a Nómada Tasks task precisely.
JavaScript Course: From Beginner to Advanced
Module 1: Introduction to JavaScript
- What Is JavaScript?
- Setting Up Your Development Environment
- Your First JavaScript Program
- JavaScript Syntax and Basic Concepts
- Variables and Data Types
- Basic Operators
- Type Conversion and Comparisons
- The Course Project: Nómada Tasks
Module 2: Control Structures
- Conditional Statements
- Loops: for, while, do-while
- Switch Statements
- Flow Control: break, continue and Nested Loops
- Error Handling with try-catch
Module 3: Functions
- Defining and Calling Functions
- Function Expressions and Arrow Functions
- Parameters and Return Values
- Scope and Closures
- Hoisting and the Execution Context
- Higher-Order Functions
- Recursion
Module 4: Objects and Arrays
- Introduction to Objects
- Object Methods and the
thisKeyword - Arrays: Basics and Methods
- Iterating over Arrays
- Searching, Sorting and Aggregating Data: find, sort and reduce
- Array Destructuring
- Object Destructuring, Spread and Rest
- JSON and Copying Objects
Module 5: Advanced Objects and Functions
- Prototypes and Inheritance
- Classes and Object-Oriented Programming
- Encapsulation: Getters, Setters and Private Fields
- Modules: Import and Export
- Asynchronous JavaScript: Callbacks
- Promises and Async/Await
- The Event Loop and the Microtask Queue
- Iterators and Generators
Module 6: The Document Object Model (DOM)
- Introduction to the DOM
- Selecting and Manipulating DOM Elements
- Handling Events
- Propagation, Delegation and Custom Events
- Creating and Removing DOM Elements
- Rendering Lists and HTML Templates
- Handling and Validating Forms
Module 7: Browser APIs and Advanced Topics
- Local and Session Storage
- The Fetch API and AJAX
- Robust Requests: Errors, Timeouts and AbortController
- WebSockets
- Service Workers and Progressive Web Apps (PWAs)
- Essential Browser APIs
- Introduction to WebAssembly
Module 8: Testing and Debugging
- Debugging JavaScript
- Code Quality: ESLint, Prettier and Conventions
- Unit Testing with Jest
- Test Doubles: Mocks, Stubs and Spies
- Integration Testing
- End-to-End Testing with Cypress
Module 9: Performance and Optimization
- Measure Before You Optimize: DevTools and Web Vitals
- Optimizing JavaScript Performance
- Memory Management
- Efficient DOM Manipulation
- Lazy Loading and Code Splitting
Module 10: JavaScript Frameworks and Libraries
- Why Frameworks Exist
- Introduction to React
- State Management with Redux
- Vue.js Basics
- Angular Basics
- Choosing the Right Framework
