Just JavaScript· 04
Chapter 04 · Counting & Equality

Counting the
Values · I

We tour the JavaScript sky and count its inhabitants — undefined, null, the two booleans, and the eighteen quintillion numbers. The point of counting is to learn what makes one value distinct from another. That is the whole secret to equality, which comes next.

Lab · floating-point precision

The further from zero, the wider the gaps

JavaScript numbers have limited precision, like a scanner that knows only sixteen million colors. Drag the magnitude up. Watch the distance between two adjacent representable numbers grow — until even consecutive integers can no longer all be stored.

magnitude ≈ 2^01
gap between neighbours2⁻⁵²
every integer exact?yes
✓ integers are exact here
01

Studying from the inside

We describe the JavaScript world on its own terms — not how an engine stores bytes. Each value is just a value, never a "pointer" or a "memory cell".

There are two ways to study this universe. From the outside, you ask how the engine "really" works — that a string is a run of bytes on a silicon chip. We take the other road. We stand inside the universe and observe its laws like physicists, without asking whether it's "real".

Why bother? Because the implementation answer changes constantly — sometimes mid-program. If you heard a tidy story about how JavaScript "really" represents numbers or objects, it is probably wrong. So set aside intuitions about passing by reference, stack allocation, and copy-on-write. The foundation is simpler: the world is full of values, each value has a type, some types are primitive (and therefore immutable), and variables are wires.

It's turtles all the way down

"Are the stars still there when I blink? I shrug. Implementation details." A value is good enough. Don't let memory metaphors distract you from an accurate, high-level model.

02

The lonely values: undefined & null

Two types have exactly one value each. They look like absence, but they are real values — and real troublemakers.

Undefined

The Undefined type has a single value: undefined. Despite the name, it is very much there. Like a black hole, it spells trouble — reading a property off it breaks your program:

let person = undefined;
console.log(person.mood); // TypeError!

It means an unintentionally missing value. It shows up on its own when JavaScript doesn't know what you wanted — for example, a declared-but-unassigned variable points at it. Don't read it as "not yet defined", though. Reading a genuinely undeclared name is a different failure entirely:

// declared, unassigned → undefined
let bandersnatch;
console.log(bandersnatch); // undefined

// never declared → ReferenceError, unrelated to undefined
console.log(jabberwocky); // ReferenceError!
let jabberwocky;

Null

null is undefined's sister. It also throws a fuss when you touch its properties, and it is the only value of its type. It is also a liar:

console.log(typeof(null)); // "object" — a lie!

Do not fall for it. null is a primitive and behaves nothing like an object. typeof null is a historical accident we live with forever. By convention, null marks an intentionally missing value — which lets you distinguish a bug (likely undefined) from valid empty data (null). The language does not enforce this; some people avoid both. I don't blame them.

typeof null === "object"

This is the single most famous bug in the language. null is primitive. The string "object" is the lie; the behaviour is the truth.

03

Booleans: only two of them

Like day and night, the Boolean type has exactly two values: true and false.

let isSad = true;
let isHappy = !isSad;            // the opposite → false
let isFeeling = isSad || isHappy; // at least one true? → true
let isConfusing = isSad && isHappy;// both true? → false
Think first

Sketch the wires for the snippet above. How many distinct boolean values appear on your diagram?

Answer · exactly two

Four variables, but only onetrue and onefalse in the whole universe. isHappy and isConfusing both land on the same false; isSad and isFeeling both land on the same true. Regardless of how booleans are stored, in our model there are only two of them.

04

Numbers: a math for computers

JavaScript numbers are floating-point. There are about eighteen quintillion of them, and they crowd together near zero and spread apart far from it.

This snippet surprises everyone the first time:

> console.log(0.1 + 0.2 === 0.3);
> console.log(0.1 + 0.2 === 0.30000000000000004);

This is not a JavaScript bug — it is floating-point math, the same in most languages. Think of a scanner: it knows at most sixteen million colours, so two almost-identical reds get rounded to the same one. JavaScript treats numbers the same way. Real math has infinitely many numbers; floating-point has only ~18 quintillion, so it snaps every value to the nearest one it knows.

Precision is densest near 0 and thins out as you move away — exactly what the lab above shows. Eventually two neighbouring numbers sit more than 1 apart, so not every integer survives:

console.log(Number.MAX_SAFE_INTEGER);     // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1); // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2); // 9007199254740992 (!)
console.log(Number.MAX_SAFE_INTEGER + 3); // 9007199254740994

Every whole number between MIN_SAFE_INTEGER and MAX_SAFE_INTEGER is exact — which is why 10 + 20 === 30. But 0.1 and 0.2 are already the nearest available numbers, not exactly themselves, and those tiny errors accumulate.

Special numbers

Floating-point also defines a few oddities for results like 1 / 0. You rarely write them on purpose, but a mistake can summon them:

expressionresultnote
1 / 0Infinitytoo big to represent
-1 / 0-Infinitythe negative end
0 / 0NaNinvalid math
1 / -Infinity-0yes, negative zero

NaN — "not a number" — is the strangest. It claims to be a number:

console.log(typeof(NaN)); // "number"

No trick here. From JavaScript's view NaN is a numeric value — not a string, not null. It is simply the number that represents an invalid numeric result. We will meet it again in Equality, where it breaks one of the rules.

05

Recap · the count so far

  • Undefined: one value, undefined — unintentionally missing.
  • Null: one value, null — intentionally missing, and typeof null lies "object".
  • Booleans: two values, true and false.
  • Numbers: one value per floating-point number — denser near 0, sparser far away.
  • Numbers from invalid math (1/0, 0/0) are special: NaN, Infinity, -Infinity, -0. typeof NaN is "number".

Counting is really about distinctness — knowing when two things are the same value or two different ones. In Part II we finish the tour (BigInts, strings, objects, functions) and then cash it all in on equality.