JavaScriptData Types

Data Types

Every value in JavaScript belongs to a type. The language has seven primitive types plus objects, and that small list covers everything you'll work with — numbers, strings, booleans, arrays, dates, DOM nodes, promises, functions. Knowing what type a value is, and what category of type it belongs to, is the foundation of avoiding a whole class of bugs.

The seven primitives
  • string — text, e.g. "hello" or hi, ${name}.

  • number — 64-bit floats, including NaN and Infinity. The same type covers 42, -1, 3.14 and 0.1 + 0.2.

  • booleantrue or false.

  • undefined — the default value of declared-but-unassigned variables and missing function arguments.

  • null — an intentional "nothing here yet" you assign on purpose.

  • bigint — arbitrarily large integers, written with a trailing n: 9007199254740993n.

  • symbol — unique, hashable values often used as private object keys.

Everything else — arrays, plain objects, functions, dates, maps, regexes, DOM elements — is an object. That gives us our 8th category.

typeof — checking a value's type

The typeof operator returns a string describing the type of its operand.

JS
typeof "hello";        // "string"
typeof 42;             // "number"
typeof true;           // "boolean"
typeof undefined;      // "undefined"
typeof 10n;            // "bigint"
typeof Symbol("id");   // "symbol"

typeof null;           // "object"   <- famous quirk
typeof [];             // "object"
typeof {};             // "object"
typeof (() => {});     // "function" <- the one object subtype with its own label
`typeof null === 'object'`
This is a bug from the very first JavaScript engine — `null` should arguably report `"null"`, but fixing it would break the web. To check for null, compare directly: `value === null`. To distinguish arrays from objects, use `Array.isArray(value)`.
A reference table

Quick reference

Text
Category   | Type        | Example              | typeof
-----------|-------------|----------------------|-------------
primitive  | string      | "hi"                 | "string"
primitive  | number      | 3.14, NaN, Infinity  | "number"
primitive  | boolean     | true, false          | "boolean"
primitive  | undefined   | undefined            | "undefined"
primitive  | null        | null                 | "object"   (!)
primitive  | bigint      | 9999999999999999n    | "bigint"
primitive  | symbol      | Symbol("id")         | "symbol"
object     | plain obj   | { a: 1 }             | "object"
object     | array       | [1, 2, 3]            | "object"
object     | function    | function () {}       | "function"
object     | date        | new Date()           | "object"
object     | map/set     | new Map(), new Set() | "object"
object     | regex       | /^a/                 | "object"
Primitives vs reference types

Primitives are immutable and copied by value. Objects are mutable and copied by reference. This single distinction explains a lot of surprising behaviour.

By value — primitives

JS
let a = 5;
let b = a;     // b is a copy of the value
b = 99;
console.log(a, b); // 5 99 — changing b does NOT change a

By reference — objects

JS
let user1 = { name: "Ada" };
let user2 = user1;          // both point at the same object
user2.name = "Lin";
console.log(user1.name);    // "Lin" — they're the same object!
Lin

user1 and user2 are two variables holding the same reference. Mutating through one is visible through the other. To get an independent copy, clone the object.

Cloning an object (shallow)

JS
const original = { name: "Ada", tags: ["admin"] };

const shallow = { ...original };
shallow.name = "Lin";
console.log(original.name); // "Ada" — safe

shallow.tags.push("vip");
console.log(original.tags); // ["admin", "vip"] — NOT safe — nested still shared

Spread (...) copies the top level only. For a deep copy, use structuredClone(value) (built-in, modern) or a library function. We dig into this in Objects and Arrays.

Equality and types

Two primitives with the same value are equal. Two objects are equal only if they are the same reference.

JS
"hello" === "hello";        // true — same string value
[1, 2] === [1, 2];          // false — two different arrays, different references

const a = [1, 2];
const b = a;
a === b;                    // true — same reference
Special numeric values

number covers everything from integers to floats. A few values are worth knowing:

JS
Number.MAX_SAFE_INTEGER; // 9007199254740991
1 / 0;                    // Infinity
-1 / 0;                   // -Infinity
0 / 0;                    // NaN  ("not a number")

NaN === NaN;              // false  (!)
Number.isNaN(NaN);        // true

Beyond MAX_SAFE_INTEGER, ordinary numbers lose precision — reach for bigint. NaN is the only value that is not equal to itself, so always test it with Number.isNaN.

null vs undefined

Two values that mean "no value", with a soft convention:

  • undefined is what JavaScript gives you when nothing is assigned yet: a missing function argument, an unset property, a return without a value.

  • null is what you assign to mean "intentionally empty". Functions that fail to find something often return null.

Modern guidance
Many style guides recommend "let JavaScript give you `undefined`, you produce `null` if you want to be explicit about emptiness". The nullish coalescing operator `??` treats both the same, so you can stop worrying about the difference in most reading code.
Wrapper objects

Primitives are not objects, but they act like objects when you use a method on them. The engine briefly wraps the primitive in a temporary object so you can call the method.

JS
"hello".toUpperCase();   // "HELLO"
(3.14).toFixed(1);       // "3.1"

Avoid new String("x"), new Number(3), new Boolean(false) — they create actual objects, which are truthy and compare by reference. The shorter, primitive forms are what you want.

The mental model that pays off
When you read a line, ask: *is this a primitive or an object?* Primitives behave like values you can throw around freely. Objects behave like nodes on a graph — passing them around shares them. That one question prevents most "why did this change?" bugs.