Data Types

Identify and understand JavaScript's major data types, including all primitive types and objects, and the difference between primitive and reference values.

Every value in JavaScript has a type, and JavaScript groups its types into two fundamentally different categories — primitives and objects — that behave differently when stored, copied, and compared.

The primitive types

JavaScript has seven primitive types. A primitive is a simple, immutable value with no methods or properties of its own (though JavaScript temporarily "wraps" primitives to let you call methods like .toUpperCase() on a string).

• string — text, written in quotes: "hello", 'world', or template • number — all numeric values, both integers and decimals: 42, -7, 3.14 • bigint — integers of arbitrary size beyond what number can safely represent, written with an n suffix: 123456789012345678901234567890n • boolean — true or false, used for logical conditions • undefined — the automatic value of a variable that has been declared but not yet assigned • null — an intentional, explicit "no value", assigned by a developer • symbol — a unique, unforgeable value, mainly used as a special kind of object property key

The object type

Everything that is not one of the seven primitives above is an object. This includes plain objects ({ name: "Sam" }), arrays ([1, 2, 3]), functions, dates, regular expressions, and more — arrays and functions are technically specialized kinds of objects.

An object is a collection of key-value pairs (for a plain object) or indexed values (for an array), and unlike primitives, objects are mutable — their contents can be changed after creation without creating an entirely new object.

Checking types with typeof

The typeof operator returns a string naming a value's type, and it is the most common way to inspect a value's type at runtime: typeof "hi" is "string", typeof 42 is "number", typeof true is "boolean", typeof undefined is "undefined".

One famous quirk to know: typeof null returns "object", not "null". This is a long-standing bug in the language dating back to its earliest implementation, kept for backward compatibility — so typeof alone cannot be used to reliably detect null; you must compare directly with === null instead.

Primitive values vs reference values

This distinction is one of the most important ideas in the entire language. A primitive value is copied by value: when you assign a primitive to a new variable, or pass it to a function, a completely independent copy is made, and changing the copy never affects the original.

An object (including arrays and functions) is copied by reference: the variable does not hold the object itself, but a reference (essentially an address) pointing to where the object lives in memory. When you assign an object to a new variable, both variables now point to the exact same underlying object — changing it through one variable is visible through the other, because there is really only one object.

typeof and value literals

typeof is an operator, not a function — parentheses are optional: typeof x and typeof(x) both work. Arrays report typeof "object" — use Array.isArray(value) to specifically detect arrays.

typeof "text";        // "string"
typeof 42;             // "number"
typeof 10n;            // "bigint"
typeof true;           // "boolean"
typeof undefined;      // "undefined"
typeof null;           // "object"  (a famous long-standing quirk)
typeof Symbol("id");   // "symbol"
typeof { a: 1 };        // "object"
typeof [1, 2, 3];       // "object"
typeof function () {};  // "function" (a special case for callable objects)

Code Examples

This walks through five common primitive values and confirms their types with typeof, including the classic null quirk. Expected result: string number boolean undefined object typeof cleared logs "object" even though cleared holds null — a well-known historical bug in JavaScript.

This is the clearest possible demonstration of primitive vs reference behavior: changing the number copy leaves the original untouched, but changing the object through obj2 also changes obj1 because they point to the same object in memory. Expected result: 10 20 20 20 let obj2 = obj1; does not copy the object — it copies the reference, so obj1 and obj2 point to the same object.

Common mistake: Assuming let obj2 = obj1; creates an independent copy of an object is a very common bug source — to truly copy an object you need something like { ...obj1 } or structuredClone(obj1).

let name = "SampleApp";
let version = 2;
let isLive = true;
let nothingYet;
let cleared = null;

console.log(typeof name, typeof version, typeof isLive, typeof nothingYet, typeof cleared);
// Primitive: copied by value
let a = 10;
let b = a;
b = 20;
console.log(a, b); // a is unaffected

// Object: copied by reference
let obj1 = { score: 10 };
let obj2 = obj1;
obj2.score = 20;
console.log(obj1.score, obj2.score); // both change

Primitive vs reference storage

Primitives are duplicated on assignment; objects share the same underlying data through a reference.

PRIMITIVE (copied by value)          OBJECT (copied by reference)

let a = 10;                          let obj1 = { score: 10 };
let b = a;   // b gets its own 10    let obj2 = obj1; // same reference

 a: [10]        b: [10]              obj1 --\
 (independent)  (independent)                 >--> { score: 10 }  (one object)
                                      obj2 --/

Important Rules

JavaScript has seven primitive types: string, number, bigint, boolean, undefined, null, and symbol; everything else is an object.

Primitives are immutable and copied by value; objects (including arrays and functions) are mutable and copied by reference.

typeof null incorrectly returns "object" — a known language quirk, not a bug in your code.

To compare or check for null specifically, use === null rather than relying on typeof.

Where this shows up

Bugs caused by misunderstanding primitive vs reference behavior — like accidentally mutating a shared object, or expecting a function to not affect data passed into it — are among the most common real-world JavaScript bugs, especially in UI frameworks like React where object identity affects when the screen re-renders.

if (typeof value === "object" && value !== null) { /* assume it's a plain object */ }

Use Array.isArray(value) to specifically check for arrays, since arrays also report typeof "object".

typeof cannot distinguish a plain object from an array (or other object subtypes) — both report "object".

[Multiple Choice] What does typeof null return, and why is it notable? A. "null" — it correctly identifies null as its own type B. "undefined" — because null and undefined are treated identically C. "object" — a long-standing quirk in JavaScript, kept for backward compatibility D. It throws a TypeError

C. "object" — a long-standing quirk in JavaScript, kept for backward compatibility — typeof null returns "object" due to a bug present since JavaScript's earliest implementation that has been preserved ever since to avoid breaking existing code.

[Predict the Output] What is logged? let arr1 = [1, 2, 3]; let arr2 = arr1; arr2.push(4); console.log(arr1.length); A. 3 B. 4 C. undefined D. TypeError

B. 4 — Arrays are objects and are copied by reference, so arr2 refers to the exact same array as arr1; pushing onto arr2 also changes what arr1 sees, giving a length of 4.

Predict the output, then verify: let x = 5; function change(val) { val = 99; } change(x); console.log(x); — and explain why, in terms of primitive vs reference values.

let x = 5; function change(val) { val = 99; // only changes the local copy } change(x); console.log(x); // 5 — x is unaffected because primitives are passed by value

Numbers are primitives, so they are passed into functions as independent copies.