Menu
Try in Playground

JavaScript Primitive Types: The Seven Built-In Values

The seven primitive types in JavaScript — string, number, bigint, boolean, null, undefined, symbol — and how they differ from objects.

Seven Primitives and Everything Else

JavaScript sorts values into two camps. On one side, seven primitive types — simple, immutable values. On the other side, objects — everything composite, mutable, or callable. That's the whole type system at the value level.

The seven primitives:

index.js
Output
Click Run to see the output here.

Anything not in that list — arrays, functions, dates, regexes, plain {} — is an object. typeof gives you the type at runtime, and you'll notice the famous wart on the last line. typeof null has returned 'object' since 1995 and will never be fixed; too much existing code relies on it.

A Primitive Is a Value, Not a Container

The mental model that helps most: a primitive is its value. The number 3 isn't a box holding 3 — it's just 3. Two variables holding 3 are holding the same value, not two copies pointing at something shared:

index.js
Output
Click Run to see the output here.

Primitives compare by value. Objects compare by reference. That one distinction is behind a lot of "why is this false?" moments later on, especially when comparing arrays or objects with ===.

Primitives Are Immutable

You can't modify a primitive. Every operation that looks like mutation actually produces a new value:

index.js
Output
Click Run to see the output here.

The first call builds a new string and throws it away because nothing caught the return value. The second reassigns name. The original "ada" was never altered — couldn't be. Same with numbers: x + 1 produces a new number, it doesn't mutate x.

This is why const on a string or number is genuinely safe. The value can't change, and const stops you from reassigning the variable.

Numbers, BigInts, and Why There Are Two

JavaScript's number is a 64-bit float. That means fast arithmetic and a ceiling — integers are only exact up to Number.MAX_SAFE_INTEGER (2^53 - 1):

index.js
Output
Click Run to see the output here.

Past that threshold, integers start colliding. bigint exists for integers that need to stay exact at any size. You write one by suffixing n:

index.js
Output
Click Run to see the output here.

bigint and number don't mix in arithmetic — you'd lose the whole point of the extra precision. Reach for bigint when you're dealing with database IDs, timestamps in nanoseconds, or crypto. Regular arithmetic stays on number.

Strings Are Primitives Too

A string in JavaScript is a primitive, not an object — even though it exposes methods like .length, .slice, .toUpperCase:

index.js
Output
Click Run to see the output here.

Under the hood, when you call a method on a string, JavaScript briefly wraps it in a String object to make the method call work, then throws the wrapper away. You don't need to think about that wrapper — just know that strings behave like values (immutable, compared by value) even though they have a rich method surface.

Single quotes, double quotes, and backticks all create the same type. Backticks additionally allow interpolation and multi-line strings, which the next doc covers.

null vs undefined

Two primitives mean "no value," and they aren't interchangeable.

undefined is what you get when something was never assigned — a declared but unset variable, a missing function argument, a property that doesn't exist:

index.js
Output
Click Run to see the output here.

null is what you write when you want to say "intentionally empty":

index.js
Output
Click Run to see the output here.

The rough convention: undefined is the language's way of saying "nothing here," null is the programmer's way. Both are falsy, both fail equality with regular values, and both get their own dedicated page later.

Symbols: Unique, By Construction

symbol is the least-used primitive. Every symbol you create is unique, even if two are built from the same description:

index.js
Output
Click Run to see the output here.

Symbols are useful as object keys that can't collide with existing ones — a library can attach metadata to your objects using a symbol and be certain no other code will overwrite it. You'll meet them again around iterators and well-known symbols like Symbol.iterator.

Checking Types at Runtime

typeof handles most cases. Keep these quirks in mind:

index.js
Output
Click Run to see the output here.

For null, compare directly: value === null. For arrays, use Array.isArray(value). For "is this any primitive?" there's no single built-in, but the idiom is clear enough:

index.js
Output
Click Run to see the output here.

Primitives vs Objects: The Assignment Gotcha

One more thing worth seeing before moving on. Because primitives are values and objects are references, assignment behaves differently:

index.js
Output
Click Run to see the output here.

With primitives, b = a copies the value. With objects, y = x copies the reference — both names point at the same underlying object. Mutating through one name affects the other. This is the single biggest source of "wait, why did that change?" bugs in JavaScript.

What You Take Away

  • Seven primitives: string, number, bigint, boolean, null, undefined, symbol. Everything else is an object.
  • Primitives are immutable and compared by value; objects are mutable and compared by reference.
  • typeof tells you the type at runtime, with two quirks worth memorizing: typeof null === "object" and typeof function === "function".
  • number is a 64-bit float with an integer safety ceiling; bigint exists for exact integers past that ceiling.

Next: Strings and Template Literals

Strings are the primitive you'll touch most, and template literals (those backtick strings) make building them painless — interpolation, multi-line text, tagged templates. That's the next page.

Frequently Asked Questions

How many primitive types does JavaScript have?

Seven: string, number, bigint, boolean, null, undefined, and symbol. Everything else — arrays, functions, dates, plain objects — is an object. You can check the type of a value at runtime with typeof, with the one historical quirk that typeof null returns 'object'.

What's the difference between a primitive and an object in JavaScript?

Primitives are immutable values compared by value — two 3s are the same 3. Objects are mutable and compared by reference — two {} are distinct even if they look identical. Assigning a primitive copies the value; assigning an object copies the reference to the same underlying data.

Are JavaScript primitives really immutable?

Yes. You can't mutate a primitive in place — 'hello'.toUpperCase() returns a new string, it doesn't change the original. Reassigning a variable (x = x + 1) swaps the variable's value for a different primitive; the original value is never altered. This is why const name = 'Ada' still lets you build new strings from name.

Why does typeof null return 'object'?

It's a bug in the original 1995 implementation that was never fixed because too much code depended on the behavior. To check for null, compare with ===: value === null. To check for undefined, use value === undefined or typeof value === 'undefined'.

Learn to code with Coddy

GET STARTED