JavaScript Data Types
Every value in JavaScript has a type — and the language has exactly eight of them. Seven are primitives (immutable, compared by value), and one is object (mutable, compared by reference). Knowing this short list cold makes the rest of the language click into place.
The Eight Types
typeof "hello" // "string"
typeof 42 // "number"
typeof 9007199254740993n // "bigint"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" ← famous historical bug
typeof Symbol("id") // "symbol"
typeof { a: 1 } // "object"
| # | Type | Category | Example |
|---|---|---|---|
| 1 | string |
primitive | "hello", 'a', `hi` |
| 2 | number |
primitive | 42, 3.14, NaN, Infinity |
| 3 | bigint |
primitive | 9007199254740993n |
| 4 | boolean |
primitive | true, false |
| 5 | undefined |
primitive | undefined |
| 6 | null |
primitive | null |
| 7 | symbol |
primitive | Symbol("id") |
| 8 | object |
reference | {}, [], function(){}, new Date() |
That’s it — there isn’t a ninth type hiding anywhere.
Primitives vs Objects
Primitives are immutable and compared by value. Objects are mutable and compared by reference.
// Primitive comparison
"hi" === "hi" // true — same value
let a = 5, b = 5;
a === b // true
// Object comparison
{ a: 1 } === { a: 1 } // false — different objects in memory
let x = { a: 1 };
let y = x;
x === y // true — same reference
PRIMITIVE OBJECT
let a = 5 ┌───┐ let x = {a:1} ┌───────┐
let b = a │ 5 │ ◄─a let y = x │ {a:1} │ ◄─x, y
└───┘ ◄─b └───────┘
b = 99 doesn't y.a = 99 changes
affect a what x.a sees too
let a = 5;
let b = a;
b = 99;
console.log(a, b); // 5 99 — primitives are copied
let x = { v: 5 };
let y = x;
y.v = 99;
console.log(x.v); // 99 — same object via two names
The typeof Operator
typeof returns a string describing the operand’s type:
typeof "hi" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" ← historical bug, never fixed
typeof [] // "object" ← arrays are objects
typeof function(){} // "function" ← functions are objects too, but get their own label
typeof NaN // "number" ← yes, "Not a Number" is a number
typeof 10n // "bigint"
typeof Symbol() // "symbol"
| Quirk | Why |
|---|---|
typeof null === "object" |
Bug from 1995 — fixing it would break the web |
typeof NaN === "number" |
NaN is a numeric value meaning “invalid number” |
typeof function(){} === "function" |
Spec exception — functions are technically objects |
typeof [] === "object" |
Arrays are objects under the hood |
To distinguish arrays from plain objects, use Array.isArray():
Array.isArray([1, 2, 3]); // true
Array.isArray({ a: 1 }); // false
String
A string is a sequence of characters. Use double quotes, single quotes, or backticks — backticks unlock interpolation and multi-line.
const a = "double";
const b = 'single';
const c = `backtick: ${1 + 1}`; // "backtick: 2"
const d = `multi
line`;
Strings are immutable — methods that look like they modify a string actually return a new one:
const s = "hello";
s.toUpperCase(); // "HELLO" — new string
console.log(s); // "hello" — original unchanged
Full string coverage in chapters 14–15.
Number
JavaScript has one numeric type: a 64-bit floating point (IEEE 754). No int vs float distinction.
1
1.5
-3
1e6 // 1,000,000
1_000_000 // numeric separator for readability
0xff // hex
0b1010 // binary
0o755 // octal
Infinity
-Infinity
NaN // "Not a Number" — result of bad math
Floating point has the usual surprises:
0.1 + 0.2; // 0.30000000000000004
0.1 + 0.2 === 0.3; // false
Numbers are safe up to Number.MAX_SAFE_INTEGER (≈ 9 quadrillion). Beyond that, use BigInt. Numbers get their own chapters 16–17.
BigInt
For integers larger than 2^53. Append n to a literal, or call BigInt():
const big = 9007199254740993n;
const bigger = big * 100n;
big + 1n; // 9007199254740994n
big + 1; // ❌ TypeError — can't mix BigInt and Number
Number(big); // 9007199254740992 — loses precision!
You rarely need BigInt unless you’re working with high-precision math, crypto, or 64-bit IDs.
Boolean
Just two values:
true
false
Produced by comparisons:
5 > 3 // true
"a" === "b" // false
undefined vs null
Two ways to say “no value”, with different intents:
undefined |
null |
|
|---|---|---|
| Meaning | “Hasn’t been assigned” | “Explicitly empty” |
| Set by | The language (default) | You (the programmer) |
typeof |
"undefined" |
"object" (historical bug) |
| In JSON | Not allowed (omitted) | Allowed |
let x; // undefined — never assigned
const y = null; // null — intentionally empty
function greet(name) {
console.log(name); // undefined if you don't pass an argument
}
greet();
null == undefined // true — loose equality treats them as equal
null === undefined // false — strict equality is strict about types
Tip: Use == to check for “either null or undefined” with one comparison: if (value == null) { … }. It’s the one place loose equality is idiomatic.
Symbol
A unique, opaque value. Mainly used as collision-proof object keys.
const id = Symbol("id");
const id2 = Symbol("id");
id === id2; // false — every Symbol is unique, even with the same description
const obj = { [id]: 123 };
console.log(obj[id]); // 123
You’ll rarely create symbols yourself — but you’ll meet built-in ones like Symbol.iterator (chapter 49).
Object — Everything Else
If it’s not a primitive, it’s an object. Objects, arrays, functions, classes, Date, Map, Set, regex — all objects.
const obj = { a: 1, b: 2 }; // plain object
const arr = [1, 2, 3]; // array
const fn = () => "hi"; // function
const cls = new Date(); // class instance
const map = new Map();
const re = /^[a-z]+$/i;
Objects are reference types — assignment copies the reference, not the data. We’ll cover them in chapters 20–21.
Type Coercion
JavaScript converts types automatically when operators demand it. This is convenient but bug-prone.
"5" + 3 // "53" — + with a string concatenates
"5" - 3 // 2 — - forces numeric conversion
5 + true // 6 — true → 1
"5" == 5 // true — loose equality coerces
"5" === 5 // false — strict equality doesn't
!!"hello" // true — !! converts to boolean
+"42" // 42 — unary + converts to number
Five values are falsy — they coerce to false in a boolean context:
false 0 "" null undefined NaN
Everything else is truthy — including "0", "false", [], and {} (yes, an empty array is truthy!).
if ("0") console.log("truthy"); // logs "truthy" — non-empty string
if ([]) console.log("truthy"); // logs "truthy" — any object
if ({}) console.log("truthy"); // logs "truthy" — any object
if (0) console.log("no"); // doesn't log
if ("") console.log("no"); // doesn't log
if (null) console.log("no"); // doesn't log
| Value | Coerces to boolean |
|---|---|
false, 0, -0, 0n, "", null, undefined, NaN |
false |
| Everything else | true |
Warning: Prefer strict equality (===) and explicit conversion (Number(x), String(x), Boolean(x)) over implicit coercion. It saves debugging time.
Explicit Conversion
When you genuinely need to convert types, be explicit:
Number("42") // 42
Number("42px") // NaN
parseInt("42px") // 42 — parses leading digits
parseFloat("3.14") // 3.14
String(42) // "42"
(42).toString() // "42"
Boolean(0) // false
Boolean("hello") // true
!!"hello" // true — shorthand
A Realistic Example
function summariseUser(user) {
// Validate types defensively at boundaries
if (typeof user !== "object" || user === null) {
throw new TypeError("user must be an object");
}
const name = String(user.name ?? "anonymous"); // string
const age = Number.isFinite(user.age) ? user.age : 0; // number
const isAdmin = Boolean(user.isAdmin); // boolean
const id = user.id ?? null; // null fallback
return { name, age, isAdmin, id };
}
Explicit conversions, strict checks, and ?? (nullish coalescing) instead of || keep this code predictable.
Best Practices Checklist
- ✅ Know the eight types cold — string, number, bigint, boolean, undefined, null, symbol, object
- ✅ Use
===and!==, not==and!=(exceptx == null) - ✅ Convert types explicitly (
Number(x),String(x)) - ✅ Use
Array.isArray()to test for arrays - ✅ Default to
??over||when checking for null/undefined - ❌ Don’t rely on implicit coercion in conditions
- ❌ Don’t use
typeofto test for null (it returns"object") - ❌ Don’t compare floating-point numbers for exact equality
What’s Next?
You know what kinds of values exist. Next, let’s learn the operators that combine and compare them — arithmetic, logical, comparison, and the modern goodies like ?? and ?..