The shape of a program
Expressions produce values, statements do things, and knowing which is allowed where explains most early syntax errors.
English has phrases and sentences. "The sum of two and three" names something; it does not ask you to do anything. "Write down the sum of two and three" is an instruction, and it has a phrase inside it.
A program is built the same way, out of two kinds of thing that fit inside each other. Run this and look at what is inside the brackets on each line.
Replace Math.max(4, 9) with Math.max(4, 9) + 1 and run it again. Whatever you put there has to end up as one value.
Four different-looking things, and each one collapsed into a single value before console.log ever saw it. That is what they have in common.
An expression is any piece of code that produces a value. 42 is an expression. So is "ab", so is 2 + 3, so is Math.max(4, 9), and so is the name price once something has been assigned to it. Expressions nest: Math.max(4, 9) + 1 is an expression containing two smaller ones.
A statement is an instruction the program carries out. A program is a list of statements, run from the top down. Statements do not produce values; they make something happen.
Add a fourth line, total = total * 2;, and predict the number before you run it.
Three statements. The first declares a name and gives it a value, and it has the expression 2 + 3 inside it. The second assigns, and has total + 1 inside it. The third is a call followed by a semicolon.
That third one is worth a name of its own. A call like console.log(total) is an expression: it produces a value, which happens to be undefined. Writing it on a line by itself with a semicolon turns it into an expression statement: an expression evaluated for what it does rather than for what it gives back.
Which is allowed where
The brackets of a call want an expression, because a value has to be handed over. Putting a statement there is not a subtle mistake that produces a strange answer; the program refuses to start.
console.log(const x = 1);
// SyntaxError: Unexpected token 'const'Read that message as "I was reading the arguments of a call, which have to be values, and const can never be one". The fix is to split it into two statements: declare on one line, print on the next.
| Position | What goes there |
|---|---|
| Inside the brackets of a call | An expression, one per argument |
After the = of a declaration | An expression |
| The top level of a file | Statements |
The body of an if or a loop | One statement, almost always a block |
Blocks
Move the const message line above the opening brace and run it again. The last line changes.
A block is a pair of curly braces { } holding zero or more statements. The whole block counts as one statement, which is why it can go anywhere a single statement is allowed.
The last line printed undefined rather than the message. Names declared with const inside a block stop existing at the closing brace. That is called block scope, and it has a lesson of its own later in this section.
You will rarely write a bare block like that one. Blocks matter because they are the body of nearly everything else: what comes after an if, what a loop repeats, what a function does.
if (ready) {
console.log("go");
}
function twice(n) {
return n * 2;
}Is console.log("hi") an expression or a statement?
Both, depending on where you look. console.log("hi") on its own is a call, which is an expression producing undefined. Written on a line and finished with a semicolon it is an expression statement. This is why you can pass a call as an argument to another call, console.log(Math.max(1, 2)), but cannot pass a declaration.