How JavaScript Runs Your Code, One Line at a Time
JavaScript runs your program one line at a time, top to bottom. See it happen on a music box that reads code, and learn why a variable only knows the past.
TechWebster5 min read
Here are four lines of JavaScript. Before you read on, decide what the last line prints.
let a = 2;
let b = a;
a = 5;
console.log(b);
If you said 5, you are in good company. Most people who are new to JavaScript expect b to follow a, because they read the program as one big description of how things should be. The real answer is 2, and the reason is the most basic idea in programming, the one almost every tutorial skips: a program runs one line at a time, from top to bottom, and each line only sees what the lines before it have already done.
This post shows that happening, step by step, on a machine you can play with.
The Short Answer
JavaScript does not read your whole program and work out the answer. It starts at line 1, does exactly what that line says, then moves to line 2, and so on.
So when line 2 runs, a holds 2, and line 2 copies that 2 into b. Line 3 then changes a to 5, but nothing tells b about it. b got its value a line earlier, and it keeps it. By the time line 4 runs, b is still 2.
Meet the Machine
Below is a music box that reads code. The program is punched on a card, one row per line. Press Space, press the down arrow or tap the figure to run the next line, and press the up arrow to step back.
Reading head, the line running nowTray, a variableCard, the value in itOnly the row inside the lit frame does anything. Line 2 copies the card that is in a at that moment, a 2, into b. Line 3 swaps a's card for a 5, but b's copy was made a line earlier, so line 4 prints 2.
Each part of the machine stands for one idea:
| Part of the machine | What it is in JavaScript |
|---|---|
| The punched card | Your program. One row is one line. |
| The lit frame, the reading head | The line running right now. Only this row does anything. |
| A tray in the rack | A variable. It appears the first time let names it. |
| The card in a tray | The value the variable holds right now. |
| The bell and the paper strip | console.log, printing a value. |
| The crank | You, running the program one line at a time. |
Running the Four Lines
Line 1: let a = 2;
let creates a variable called a, and = 2 puts the value 2 into it. On the machine, a tray labelled a slides into the rack and a card reading 2 drops into it.
Line 2: let b = a;
This is the line that matters. let b creates a second variable. Then = a means look at what is in a right now, and put a copy of it into b. On the machine, a copy of the 2 card lifts out of tray a and flies across to tray b.
After this line, the two trays each hold their own card. They are not connected.
Line 3: a = 5;
There is no let this time, so no new tray appears. This line changes a variable that already exists: tray a gets a new card reading 5. Watch tray b while it happens. It does not move.
Line 4: console.log(b);
The machine looks in tray b, finds the 2 that was copied on line 2, rings the bell, and prints 2.
Three Ideas to Keep
1. Order is everything. The same lines in a different order give a different result. Swap lines 2 and 3 and the program prints 5, because the copy is made after a has changed.
2. = means "put", not "equals". In maths, b = a says the two are the same forever. In JavaScript, b = a is an action that happens once: take the value in a, put it in b, and move on. Reading = as "becomes" or "gets" helps: "b gets a".
3. A variable only knows the past. When a line runs, it can only use values that earlier lines have already put in place. Nothing written further down has happened yet.
Try It Yourself
Open your browser's console (press F12, or Cmd + Option + J on a Mac, then pick the Console tab). Paste the four lines and press Enter. You will see 2.
Now try these changes, and predict each answer before you run it:
- Swap lines 2 and 3. What prints?
- Add
console.log(a);as a fifth line. What prints? - Move
console.log(b);up to the very top. What happens?
The answers are at the end of the post.
Common Mistakes
Using a variable before the line that creates it. If line 1 is console.log(b);, JavaScript has not reached let b yet, so it stops with an error: ReferenceError: Cannot access 'b' before initialization. The machine has no tray for b yet.
Expecting a copy to update itself. After let b = a;, changing a does not change b. They are two trays with two cards.
Thinking every line runs at once. Each line runs, finishes, and only then does the next one start. That habit of reading code one line at a time, and asking "what do the trays hold now?", is how experienced developers find bugs.
Check Yourself
What does each of these print?
let x = 10;
let y = x;
x = x + 1;
console.log(x, y);
let score = 0;
score = score + 5;
score = score + 5;
console.log(score);
let first = "tea";
let second = "coffee";
first = second;
second = "water";
console.log(first);
Answers. The first prints 11 10: y copied the 10 before x changed. The second prints 10: each line adds to whatever score holds at that moment. The third prints coffee: first copied second while it still held "coffee", and changing second afterwards does not reach back.
Answers to Try It Yourself. Swapping lines 2 and 3 prints 5. With a fifth line console.log(a);, you see 2 from line 4 and then 5. Moving console.log(b); to the top throws a ReferenceError, because b does not exist yet.
What this machine does not show
Every card in this post held a number, so copying it made a second, separate card. Objects and arrays behave differently: copying one copies a pointer to the same card, not a second card. A line can also wait, for a timer or for data from a server, and JavaScript does not freeze while it waits. Neither of those is a post on this site yet.
If you are following a learning path, this post fits alongside the first sections of our JavaScript syllabus for beginners.