Data Types in JavaScript
The 7 primitives, objects, reference vs value, typeof quirks, and real-world type checking
Last updated on
JavaScript is dynamically typed — you don't declare types, the engine figures them out at runtime. Understanding data types deeply is essential for avoiding subtle bugs.
Two Categories
Data Types
├── Primitives (stored by VALUE)
│ ├── String
│ ├── Number
│ ├── BigInt
│ ├── Boolean
│ ├── Undefined
│ ├── Null
│ └── Symbol
│
└── Non-Primitives (stored by REFERENCE)
├── Object
├── Array
├── Function
├── Date
├── Map / Set
├── WeakMap / WeakSet
└── RegExpThe 7 Primitive Types
String
const single = 'hello';
const double = "hello";
const template = `Hello, ${name}!`; // template literal (ES6)
// Strings are IMMUTABLE
const str = "hello";
str[0] = "H"; // Does nothing — no error, but doesn't change
console.log(str); // "hello"Number
JavaScript has one number type for both integers and decimals (64-bit IEEE 754 floating point).
const age = 25; // integer
const price = 19.99; // decimal
const negative = -10;
const infinity = Infinity;
const notANumber = NaN; // "Not a Number" — but typeof NaN is "number" 🤯
// Safe integer range
console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 (2^53 - 1)
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991BigInt
For numbers larger than Number.MAX_SAFE_INTEGER:
const big = 9007199254740991n; // Note the 'n' suffix
const huge = BigInt("123456789012345678901234567890");
// Cannot mix BigInt and Number
big + 1; // ❌ TypeError
big + 1n; // ✅ 9007199254740992nBoolean
const isActive = true;
const isDeleted = false;Undefined
A variable that has been declared but not assigned a value:
let x;
console.log(x); // undefined
function greet(name) {
console.log(name);
}
greet(); // undefined (no argument passed)Null
An intentional absence of value. You set it explicitly:
let user = null; // "there is no user right now"
// Later...
user = { name: "Shiva" }; // now there's a userSymbol
Creates a unique identifier — no two symbols are the same:
const id1 = Symbol("id");
const id2 = Symbol("id");
console.log(id1 === id2); // false — always unique
// Primary use: object property keys that won't collide
const SECRET = Symbol("secret");
const obj = {
[SECRET]: "hidden value",
name: "visible"
};
console.log(obj[SECRET]); // "hidden value"
console.log(Object.keys(obj)); // ["name"] — Symbol keys are hiddenNon-Primitive Types (Reference Types)
Object
const user = {
name: "Shiva",
age: 25,
address: {
city: "Mumbai",
country: "India"
}
};Array (technically an object)
const colors = ["red", "green", "blue"];
console.log(typeof colors); // "object" — not "array"!
console.log(Array.isArray(colors)); // true — correct way to checkFunction (technically an object)
function greet() {
return "hello";
}
console.log(typeof greet); // "function" — special typeof caseValue vs Reference — The Most Common Bug Source
Primitives are Copied by Value
let a = 10;
let b = a; // b gets a COPY of 10
b = 20;
console.log(a); // 10 — unchangedObjects are Copied by Reference
const obj1 = { name: "Shiva" };
const obj2 = obj1; // obj2 points to the SAME object
obj2.name = "Alex";
console.log(obj1.name); // "Alex" — BOTH changed!Visual:
Primitives: Objects:
a → [10] obj1 → ┐
b → [20] obj2 → ┤→ { name: "Alex" }
(separate boxes) (same box)How to Actually Copy an Object
// Shallow copy (1 level deep)
const copy1 = { ...obj1 };
const copy2 = Object.assign({}, obj1);
// Deep copy (all levels)
const deepCopy = structuredClone(obj1); // Modern — use this!
const jsonCopy = JSON.parse(JSON.stringify(obj1)); // Old way — loses functions, dates, undefinedThe typeof Operator and Its Quirks
typeof "hello" // "string"
typeof 42 // "number"
typeof 42n // "bigint"
typeof true // "boolean"
typeof undefined // "undefined"
typeof Symbol() // "symbol"
typeof {} // "object"
typeof [] // "object" ← gotcha!
typeof function(){} // "function"
typeof null // "object" ← FAMOUS BUG
typeof NaN // "number" ← confusing!Why typeof null === "object"?
This is a bug from the original JavaScript implementation in 1995. In the first version, values were stored as a type tag + value. Objects had a type tag of 0, and null was represented as the NULL pointer (0x00) — so its type tag was also 0, making typeof null return "object".
It was never fixed because too much existing code depends on this behavior.
Proper Type Checking Patterns
// Check for null
value === null
// Check for undefined
value === undefined
// or
typeof value === "undefined"
// Check for null OR undefined
value == null // true for both null and undefined (one of the few good uses of ==)
// Check for array
Array.isArray(value)
// Check for NaN
Number.isNaN(value) // ✅ Use this
isNaN(value) // ❌ Avoid — isNaN("hello") returns true (coerces first)
// Check for plain object
typeof value === "object" && value !== null && !Array.isArray(value)
// Check instance type
value instanceof Date
value instanceof RegExp
value instanceof MapTruthy and Falsy Values
Every value in JavaScript is either truthy or falsy when used in a boolean context.
The 8 Falsy Values (Memorize These)
false
0
-0
0n // BigInt zero
"" // empty string
null
undefined
NaNEverything else is truthy, including:
"0" // truthy (non-empty string)
" " // truthy (space is a character)
[] // truthy (empty array)
{} // truthy (empty object)
function(){} // truthyReal-World Pattern
// Using truthy/falsy for defaults
const username = inputValue || "Anonymous";
// Better: nullish coalescing (handles 0 and "" correctly)
const count = inputCount ?? 0;
// inputCount = 0 → count = 0 (preserves 0)
// inputCount = null → count = 0 (falls back)Interview Deep-Dives
Q: What's the difference between undefined and null?
undefined | null | |
|---|---|---|
| Meaning | Variable declared but not assigned | Intentional absence of value |
| Set by | JavaScript engine | The developer |
| typeof | "undefined" | "object" (bug) |
| In math | NaN (undefined + 1) | 0 (null + 1) |
Q: Why is NaN !== NaN?
console.log(NaN === NaN); // falseThis is by design (IEEE 754 standard). NaN represents "the result of a failed math operation" — and two different failed operations shouldn't be considered equal.
// Correct way to check for NaN
Number.isNaN(NaN); // true
Number.isNaN("abc"); // false (doesn't coerce)