All topics
Fundamentalsintermediate

Symbol and BigInt Primitives

Two newer primitive types: Symbol for guaranteed-unique property keys, and BigInt for integers beyond Number's safe range.

Two primitives added later, each solving a specific problem.

A Symbol is like a one-of-a-kind serial number stamped on an item — even if two items have the same product name, their serial numbers are guaranteed to be different. BigInt is like switching from a calculator with a fixed digit display to a full ledger book — you trade a bit of convenience for the ability to write numbers of any size without rounding.

Key Concepts

1
A symbol is a guaranteed-unique value.
    const a = Symbol('id');
    const b = Symbol('id');
    a === b            // false -- the string is only a label
2
Which makes it safe as a property key.
    const HIDDEN = Symbol('internal');
    obj[HIDDEN] = 'data';
3
    Object.keys(obj)              // does not include it
    JSON.stringify(obj)           // does not include it
    for (const k in obj)          // does not include it
4
So a library can attach data to an object a consumer owns, with no chance of colliding with their keys and without it appearing in their serialisation.
5
Well-known symbols hook into language behaviour.
    Symbol.iterator      makes an object usable in for...of
    Symbol.asyncIterator for await...of
    Symbol.toPrimitive   controls coercion
    Symbol.toStringTag   what Object.prototype.toString reports
6
    obj[Symbol.iterator] = function* () { yield 1; yield 2; };
    [...obj]    // [1, 2]
7
That is how a custom object becomes iterable — the reason for...of works on arrays, strings, Maps and Sets is that they all define it.
for...of
8
Symbol.for uses a global registry, for the rare case where two separate pieces of code need the same symbol.
Symbol.for
9
BigInt is for integers beyond Number's safe range.
    Number.MAX_SAFE_INTEGER        // 9007199254740991
    9007199254740993n              // exact, as a BigInt
Number
10
    const big = 123456789012345678901234567890n;
    BigInt('123')                  // from a string
11
It does not mix with Number.
    1n + 1          // TypeError
    1n + BigInt(1)  // 2n
    1n == 1         // true  -- loose equality coerces
    1n === 1        // false
12
The refusal is deliberate: silently converting would lose precision, which is the thing BigInt exists to prevent.
13
Where it is actually needed. Large database ids, cryptographic values, high-precision timestamps, and anything beyond 2^53. For ordinary arithmetic it is slower and unnecessary.
14
And the practical note. JSON.stringify throws on a BigInt. Serialising one means converting it to a string deliberately, which is also why APIs send large ids as strings in the first place.
JSON.stringify
15
What the interviewer is probing.1. "What is a Symbol for?" Probing: the purpose. Stalls: "A unique string." Moves up: a unique property key that cannot collide, used for metadata on objects and for protocols like Symbol.iterator.
16
2. "Can you mix BigInt and Number in arithmetic?" Probing: the rule. Stalls: "Yes." *Moves up:* no — it throws TypeError; convert explicitly, accepting the precision loss when going to Number.
17
3. "Where would you actually use BigInt?" Probing: the use case. Stalls: "Large maths." Moves up: IDs beyond 2^53, like Twitter snowflake ids or database bigints, where a Number would silently lose precision.
18
4. "Are symbol keys returned by Object.keys?" Probing: enumeration. Stalls: "Yes." *Moves up:* no — they are skipped by Object.keys and JSON.stringify, which is what makes them suitable for hidden metadata.