Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~19 min· topic 2 of 6

Topic 1.2

Primitive Types

In one line

JavaScript has seven primitive types (string, number, boolean, null, undefined, bigint and symbol) plus objects; typeof tells you a value's type, with a few famous quirks.

Think of it like this

Sorting things in a kitchen. Flour goes in the flour jar, eggs in the egg tray, milk in the fridge. You handle each kind differently: you can pour milk but not eggs. JavaScript sorts every value into a type the same way, and the type decides what you can do with it: you can add numbers, uppercase strings and say yes or no with booleans.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Type
The kind of a value, like number or string. It decides what you can do with the value.
Primitive
A simple single value (string, number, boolean, null, undefined, bigint, symbol) that can't be changed in place.
Object
Any value that isn't a primitive: arrays, functions, dates and { } objects. It can hold many values.
undefined
JavaScript's automatic "no value here".
null
A value you set on purpose to mean "empty".
Operator
A symbol or word that works on values, like +, = or typeof.
typeof
An operator that returns a value's type as a string, like "number".
Immutable
Can't be changed after it's made. Every primitive is immutable.
Reference
A pointer to an object. Copying a reference shares the same object.
Autoboxing
JavaScript briefly wrapping a primitive in an object so you can call methods on it.

Step by step

01Meet the seven primitives

Each line below creates one primitive. You'll use the first five every day.

app.jswhole filejavascript
const name = "Asha";        // string
const age = 25;             // number
const isMember = true;      // boolean
let nickname;               // undefined
const manager = null;       // null
const stars = 1000000000000n; // bigint
const id = Symbol("id");    // symbol
Meet the seven primitivesdiagram
Rendering diagram…

02Ask a value its type

typeof returns a lowercase string. Because it always returns a string, typeof typeof 42 is "string".

app.jswhole filejavascript
typeof "Asha"   // "string"
typeof 25       // "number"
typeof true     // "boolean"
typeof undefined // "undefined"
typeof 10n      // "bigint"

03Learn the quirks

typeof null is "object" (a historic bug). To test for null, compare directly: value === null. Arrays are objects, so test them with Array.isArray. Functions get their own answer, "function".

app.jswhole filejavascript
typeof null           // "object"  (bug kept forever)
typeof [1, 2]         // "object"
Array.isArray([1, 2]) // true
typeof function () {} // "function"

04Copy by value vs copy by reference

Copying a primitive copies the value itself. Copying an object copies only the reference, so both names reach the same object.

Copy by value vs copy by referencediagram
Rendering diagram…

05Methods on primitives

"cat".toUpperCase() works through autoboxing and returns a new string. The original stays "cat", which is why you must store the result: const loud = word.toUpperCase();.

Try it yourself

  1. 1

    Predict the types

    Before running the first example, add console.log(typeof "42"); and console.log(typeof 42n);. Write down your predictions, then run it.

  2. 2

    Break the sharing

    In the third example, change const q = p; to const q = { n: p.n };. Predict what p.n prints now, then run. Why is it different?

  3. 3

    Call a method on null

    Add console.log(nothing.length); at the end of the second example. Read the error in the console: which value has no properties?

Code & diagrams

typeof on every primitive New tab

Whole numbers and decimals share one type, `number`. And `null` reports `object`: that's the famous bug.

Console

(nothing was printed)

Expected console output

string
number
number
boolean
undefined
object
bigint
symbol
The quirks of typeof, and the right checks New tab

Console

(nothing was printed)

Expected console output

object
true
object
true
function
number
undefined
string
Primitives are copied, objects are shared New tab

`word.toUpperCase()` on its own line creates a new string and throws it away: strings never change in place.

Console

(nothing was printed)

Expected console output

hi hi!
2
cat
CAT
Symbols are unique, bigints are exact ES2020+ New tab

Symbols arrived in ES2015 and `description` in ES2019; BigInt in ES2020. Topic 1.3 explains why such big numbers need BigInt.

Console

(nothing was printed)

Expected console output

false
Symbol(id)
id
9007199254740994n
bigint

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Check for null with typeof

Write if (typeof user === "object") { console.log(user.name); } when user is null.

terminal
$ Console
── what you'll see ──
Uncaught TypeError: Cannot read properties of null (reading 'name')

Break #2

Use a symbol in text

Write console.log("My id is " + Symbol("id"));

terminal
$ Console
── what you'll see ──
Uncaught TypeError: Cannot convert a Symbol value to a string

Myth vs fact

Myth

Everything in JavaScript is an object.

Fact

Primitives are not objects. They only behave like objects for a moment when you call a method on them (autoboxing). null and undefined don't even do that.

Myth

null is an object because typeof null says so.

Fact

null is a primitive. typeof null === "object" is a bug from 1995 kept for compatibility. A proposal to fix it was rejected because it broke real websites.

Myth

JavaScript has separate types for whole numbers and decimals.

Fact

There is one number type for both (64-bit floating point). bigint is a separate type only for very large whole numbers.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The typeof null bug comes from the first engine's value tags: values were stored with a type tag in their low bits, objects had tag 0, and null was the null pointer (all zero bits), so it read as an object.

  • ▸

    typeof document.all is "undefined", even though it exists. It's a deliberate spec exception ([[IsHTMLDDA]]) so that very old browser-detection code keeps working. It's also the only falsy object.

  • ▸

    Engines don't really create a wrapper object on every method call: V8 calls the method on the prototype (String.prototype) directly. The wrapper is a spec model; the observable behaviour is the same.

  • ▸

    new String("a") creates a real wrapper object: typeof new String("a") is "object" and new String("a") === "a" is false. Never use new with String, Number or Boolean; call them without new to convert (Topic 1.5).

Remember this

  1. 1

    A type is a kind of value. JavaScript has eight: seven primitive types and object. A primitive is a simple, single value with no parts you can change. They are: string (text, like "hello"), number (any number, whole or decimal, like 42 or 3.14), boolean (true or false), undefined ("no value has been given"), null ("deliberately empty"), bigint (whole numbers of any size, written with an n: 10n, added in ES2020) and symbol (a unique identifier, added in ES2015). Everything else, including arrays, functions and dates, is an object.

  2. 2

    undefined and null both mean "nothing", but they are used differently. undefined is what JavaScript gives you automatically: a variable with no value, a missing object property, a function that returns nothing. null is what you write on purpose to say "empty for now", like let selectedUser = null; before anyone is selected. A good habit: let JavaScript produce undefined, and use null yourself.

  3. 3

    The typeof operator returns a string naming a value's type: typeof 42 is "number", typeof "hi" is "string". An operator is a symbol or word that works on values, like + or typeof. It has quirks you must know. typeof null is "object": a bug from the very first version in 1995 that can never be fixed because old websites depend on it. typeof a function is "function", even though functions are objects. typeof [1, 2] is "object", so use Array.isArray(value) to detect arrays. typeof NaN is "number" (Topic 1.3). And typeof a name that was never declared gives "undefined" instead of throwing an error.

  4. 4

    Primitives are immutable: no operation changes a primitive value in place. "cat".toUpperCase() doesn't change "cat"; it makes a new string "CAT". Primitives are also copied by value: let b = a gives b its own copy, so changing b later never affects a. Objects are different: const q = p makes both names point to the same object (a reference), so a change made through q shows up through p.

  5. 5

    How can a primitive have methods like .toUpperCase() if it isn't an object? When you use a dot on a string, number, boolean, bigint or symbol, JavaScript briefly wraps it in a matching wrapper object (String, Number…), calls the method, and throws the wrapper away. This is called autoboxing. null and undefined have no wrapper, which is why null.length throws a TypeError.

  6. 6

    A symbol is a value guaranteed to be unique: Symbol("id") === Symbol("id") is false. The text inside is only a description for debugging. Symbols are used as object keys that can never clash with other keys, and the language uses built-in ones such as Symbol.iterator (Topic 14.5). You'll rarely create them as a beginner, but you must recognise them.

Explain it without notes

01

Name JavaScript's primitive types. What makes a value primitive?

02

Why is typeof null equal to "object", and how do you correctly check for null and for arrays?

03

What is the difference between null and undefined?

04

How can "abc".length work if strings are not objects?

Practice

01

Log the type of each of these values: "", 0, false, [], {}, null.

02

Write two lines that prove strings are copied by value: copy a string into a second variable, change the second one, and log both.

Trade-offs

  • ↔

    Using both null and undefined lets you tell "not set yet" from "deliberately empty", but it doubles the checks; many teams pick one (often undefined) for their own code and handle both at boundaries like APIs.

Done when you can

  • I can name all seven primitive types.

  • I can use typeof and know its quirks with null, arrays and functions.

  • I can explain the difference between null and undefined.

  • I can explain copy by value vs copy by reference.

  • I know why primitives can have methods.