Just JavaScript· 05
Chapter 05 · Counting & Equality

Counting the
Values · II

We finish the tour with BigInts, strings, symbols, objects, and functions — and find the line that splits the universe in two. Writing 2 or "hi" always summons the same value. Writing {} or function(){} always creates a brand-new one. That single difference powers equality.

Lab · summon vs create

Run the same line seven times. How many values?

Pick what to log, then run it. A number literal summons the one value that always existed, so every call points at the same dot. An object or function literal creates a new value each time — so the distinct-value counter climbs.

calls0
distinct values0
01

BigInts: precision without limit

Regular numbers lose precision past 2⁵³. BigInts fill that gap — one value for every integer in math, which means infinitely many.

let alot = 9007199254740991n; // note the trailing n
console.log(alot + 1n); // 9007199254740992n
console.log(alot + 2n); // 9007199254740993n  — no rounding!

No funny business with the rounding — ideal where precision is sacred, like money. The specification gives BigInts arbitrary precision, so conceptually there is an infinite number of them, one per mathematical integer. Count von Count could count forever and never finish. (In practice the computer's memory runs out long before eternity does.)

02

Strings: text, and a value for each

Three ways to write a string, one type, and a distinct value for every conceivable string — including ones nobody has typed yet.

console.log(typeof("こんにちは")); // "string"
console.log(typeof('こんにちは')); // "string"
console.log(typeof(`こんにちは`)); // "string"
console.log(typeof(''));         // "string" (empty counts)

Strings aren't objects

Strings carry built-in properties, which makes them feel object-like. They are not. The properties are special, and they are read-only — because every primitive is immutable.

let cat = 'Cheshire';
console.log(cat.length); // 8
console.log(cat[0]);    // "C"
cat[0] = 'X';            // silently ignored / throws — no effect
A value for every conceivable string

Your grandmother's maiden name, the fanfic you deleted, the unwritten script of Matrix 5 — every possible string already exists as a value in our model. They can't all fit in memory, but the idea fits in your head. The universe is a model for humans, not for chips, so we simply say all strings "always existed" — one per distinct string.

03

Symbols: a quick wave

Symbols are a newer primitive used to hide implementation details. Their purpose is hard to explain before we cover properties, so we'll wave and move on.

let alohomora = Symbol();
console.log(typeof(alohomora)); // "symbol"

Sorry, symbols. We'll come back for you someday.

04

Objects: the ones we can make

Arrays, dates, RegExps — all objects. Objects are not primitive, so they're mutable, and crucially, every {} creates a new value.

console.log(typeof({}));        // "object"
console.log(typeof([]));        // "object"
console.log(typeof(new Date())); // "object"
console.log(typeof(/\d+/));      // "object"

The primitives we toured — null, undefined, booleans, numbers, strings — all "always existed"; we only ever summon them. Objects are different. We can make more of them. Every {} literal produces a brand-new object value that never existed before. The same goes for [] and every other object literal. This is exactly what the lab demonstrates.

Do objects disappear?

We can't destroy an object. Setting junk = null doesn't necessarily destroy anything — it just re-aims a wire.

let junk = {};
junk = null; // the object may still exist; we just stopped pointing at it

JavaScript is garbage-collected: an object may eventually vanish once no wire can reach it, on no schedule you can observe. So: we can create objects, but we can't destroy them on command. Unless you're chasing a memory leak, you can mostly forget garbage collection exists.

05

Functions are values too

Forget for a moment that functions are useful. Treat a function as just another kind of value — one that, like an object, is created fresh every time its expression runs.

Three loops, each running a line seven times. How many distinct values reach console.log?

loop bodydistinct valueswhy
console.log(2)1a number literal summons the same value each time
console.log({})7each object literal creates a new value
console.log(function(){})7each function expression creates a new value

A function expression is a question to the universe, answered by creating a new function value every time it runs — just like {}. Technically functions are objects (very special ones). If you can do a thing to an object, you can usually do it to a function too.

Pointing at a function vs calling it

What does this print?

Think first
let countDwarves = function() { return 7; };
let dwarves = countDwarves;
console.log(dwarves); // ?
Answer · the function, not 7

We created one function value and pointed countDwarves at it. Then we pointed dwarves at the same value. We never called anything — there are no (). So dwarves logs the function itself.

It's the () alone that calls. Neither let nor = has anything to do with it:

let a = countDwarves;   // point a at the function value
let b = countDwarves();  // point b at the value the function RETURNS (7)

countDwarves() is itself an expression — a call expression. To answer it, JavaScript runs the function's code and hands back the returned value.

06

Recap · the full count

typehow many valuessummoned or created?
Undefined1 · undefinedsummoned
Null1 · nullsummoned
Booleans2 · true, falsesummoned
Numbersone per floating-point numbersummoned
BigIntsone per integer (∞)summoned
Stringsone per conceivable string (∞)summoned
Symbols(skipped for now)created
Objectsone per object literal you runcreated
Functionsone per function expression you runcreated

Here's the payoff: 2 or "hello" always summons the same value, but {} or function(){} always creates a different one. That distinction is the whole basis of equality — our next chapter.