The Primitive Types

Beginner · 16 min read · ▶ live playground · ✦ checkpoint

JavaScript has only seven primitive types, the small built-in kinds of values that can't be broken into smaller JavaScript pieces. That sounds tiny, but almost every program starts by moving these seven kinds of values through names, calculations, messages, and decisions.

The seven small kinds

A type is the kind of a value, like "number" or "string". Remember the label idea from variables: the variable name is the label, but the type lives on the value the label points at.

Here is the full primitive cast:

  • A number is a numeric value like 42, 3.14, or 0.
  • A string is text wrapped in quotes, like "Ada" or "game over".
  • A boolean is one of exactly two values: true or false.
  • undefined means JavaScript has no value here yet.
  • null means you put an empty value here on purpose.
  • A bigint is a whole-number value for numbers too large for regular number; it ends with n.
  • A symbol is a guaranteed-unique token JavaScript can use as an object key, a name for one slot inside a grouped value; lesson 13.2 gives the full symbol story.

Think of primitives as sealed tokens. You can pass a token around, print it, compare it later, or put a new token under the same label. You don't open the token and rearrange its insides.

const playerName = "Mina";
const score = 42;
const hasBonus = true;
let nextOpponent;
const emptyLocker = null;
const giantScore = 9007199254740993n;
const lockerToken = Symbol("locker");
 
console.log(playerName);
console.log(score);
console.log(hasBonus);
console.log(nextOpponent);
console.log(emptyLocker);
console.log(giantScore);
console.log(lockerToken);

Mina, 42, true, undefined, null, 9007199254740993n, then Symbol(locker).

Inspecting with typeof

The fastest way to ask "what kind of value is this?" is typeof, an operator, a built-in word or symbol that tells JavaScript to perform one operation and return a result.

const playerName = "Mina";
const score = 42;
const hasBonus = true;
let nextOpponent;
const emptyLocker = null;
const giantScore = 9007199254740993n;
const lockerToken = Symbol("locker");
 
console.log(typeof playerName);
console.log(typeof score);
console.log(typeof hasBonus);
console.log(typeof nextOpponent);
console.log(typeof emptyLocker);
console.log(typeof giantScore);
console.log(typeof lockerToken);

string, number, boolean, undefined, object, bigint, then symbol.

That fifth line is the famous quirk: typeof null returns "object".

null is still a primitive. The "object" result is old behavior JavaScript keeps because changing it would break old websites. For now, just remember the exception: typeof is useful, but null is the odd one out. Lesson 4.2 shows the exact test you use when you need to check for null.

undefined vs. null

Beginners often treat undefined and null as the same kind of nothing. They aren't.

undefined is the empty slot JavaScript leaves when a value hasn't been supplied yet. null is the empty slot you fill in deliberately to say "there is no value here."

let currentCoach;
const retiredCoach = null;
 
console.log(currentCoach);
console.log(retiredCoach);
console.log(typeof currentCoach);
console.log(typeof retiredCoach);

undefined, null, undefined, then object.

Picture a tournament bracket. An empty cell the system hasn't filled in yet is undefined. A cell you mark "no opponent this round" is null. Both mean there isn't a player name in the cell, but they tell different stories.

You don't need to overuse null. Most beginner programs can let JavaScript's natural undefined do its job. Reach for null when you want the missing value to be an intentional part of your data.

Try it — make the types visible

Run this once, then change a few values. Try turning score into "42" with quotes, or hasBonus into false. Watch which type names change and which values stay put.

javascript — live consolereal engine
⌘/Ctrl + Enter to run

Primitives don't change inside

A primitive value is immutable, which means JavaScript never changes that value in place. When your code appears to "change" a primitive, the variable label moves to a new primitive value.

let chant = "go";
const louderChant = chant + "!";
 
console.log(chant);
console.log(louderChant);
 
chant = louderChant;
console.log(chant);

go, then go!, then go! — the original string did not grow an exclamation point; the name moved to a new string.

This is the same label model from variables, now applied to types. chant + "!" creates a new string value. Reassignment moves chant to that new value. The old "go" value wasn't edited.

Copying primitive values

Primitives are copied by value, which means assignment copies the actual primitive value at that moment, not a live connection to another variable.

let currentMood = "calm";
const moodAtBreakfast = currentMood;
 
currentMood = "focused";
 
console.log(currentMood);
console.log(moodAtBreakfast);

focused, then calmmoodAtBreakfast kept the old primitive value.

The analogy is a photocopy. If you photocopy a scorecard, then update the original scorecard later, the photocopy doesn't change. Primitive assignment works like that.

Objects won't work exactly this way. Objects are values that can group other values together, and everything in JavaScript that isn't a primitive belongs to the object family. Arrays and plain objects arrive later in the course, and they come with different copy behavior. For today, the dividing line is enough: primitives are small, immutable values copied cleanly by value.

You now have names for the values you've already been writing. Next, you'll zoom into the most used primitive in everyday code: numbers, including the strange reason 0.1 + 0.2 doesn't quite behave like school math.

Checkpoint

Answer all three to mark this lesson complete

+50 XP on completion