Every value in JavaScript belongs to exactly one of eight categories at the language level: seven primitives and Object. Hosts add more objects (DOM nodes, fetch responses), but the language itself is built from this split. Primitives are atomic; objects are collections of properties and optional internal methods.
The seven primitives and Object
The primitive types are undefined, null, boolean, number, bigint, string, and symbol. Each primitive is immutable. You can replace a variable that holds one primitive with another primitive, but you never mutate the bits inside 5 or "hi".
Object is the eighth type. Arrays, functions, dates, regular expressions, and plain {} literals are all objects. They are mutable: you can add, change, or delete properties on the same identity.
| Category | Examples | Mutable |
|---|---|---|
| undefined | undefined |
no |
| null | null |
no |
| boolean | true, false |
no |
| number | 42, NaN, Infinity |
no |
| bigint | 9007199254740991n |
no |
| string | "hello" |
no |
| symbol | Symbol("id") |
no |
| object | {}, [], () => {} |
yes |
See Numbers and BigInt, Strings and template literals, and Symbols in JavaScript for the types that deserve their own chapter.
typeof and what it reports
typeof is a unary operator. It returns a string naming the type of its operand. For primitives other than null, the result matches intuition:
typeof undefined; // "undefined"typeof true; // "boolean"typeof 42; // "number"typeof 42n; // "bigint"typeof "x"; // "string"typeof Symbol(); // "symbol"For any object (including arrays and functions), typeof returns "object" unless the value is callable, in which case it returns "function". Functions are objects with a [[Call]] internal method; the extra typeof case exists for historical convenience.
typeof quirks
Three results surprise people who expect typeof to mirror the spec tables exactly.
null is its own type in the language, but typeof null is "object". That is a bug from the first implementation that could not be fixed without breaking the web.
typeof null; // "object"Arrays are objects. typeof [] is "object". Use Array.isArray(value) when you need an array check.
NaN is a number value meaning “not a number.” typeof NaN is "number". Use Number.isNaN(value) after you know the value is already typed as number; it does not coerce strings the way the global isNaN does.
Wrapper objects
Each primitive except null and undefined has a corresponding wrapper object constructor: Boolean, Number, BigInt, String, and Symbol. Calling new String("a") creates an object whose internal value is the primitive "a".
In normal code you should not use these wrappers. The language boxes primitives temporarily when you read a property or method:
"hello".toUpperCase(); // "HELLO" — a String object is created, used, then discardedLoose equality between a primitive and its wrapper can be true (==), but === keeps them apart. Prefer primitives; let the engine box when needed.
Immutability and assignment
Assigning a primitive copies the value into the binding. Two variables can hold the same primitive with no shared state between them.
Objects are different: a variable holds a reference to one object identity. Copying the reference does not clone the object. Pass by value and reference in JavaScript walks through what that means for function arguments and nested structures.
Everything else behaves like an object
Host APIs expose objects. typeof document is "object" in a browser. typeof Math.sin is "function", and functions are objects you can attach properties to.
The spec also defines exotic objects (for example arrays and arguments objects) with specialized internal methods. For day-to-day reasoning, “object with extra behavior” is enough until you hit an edge case in the spec.
Series map
| Order | Chapter |
|---|---|
| 2 | Pass by value and reference |
| 3 | Type coercion and equality |
| 4 | Numbers and BigInt |
| 5 | Strings and template literals |
| 6 | Symbols in JavaScript |
| 7 | JavaScript fails |