Why Understanding Data Types Matters
JavaScript's type system is fundamental to the language, yet it's full of quirks that trip up even experienced developers. Understanding data types is crucial for:
- Writing predictable code - Knowing how values behave in memory
- Debugging effectively - Understanding why comparisons fail
- Acing technical interviews - Data types are a favorite interview topic
- Avoiding common bugs - Type coercion and reference issues
This guide covers everything you need to know about JavaScript data types, from the basics to advanced interview questions.
The Two Categories: Primitive vs Reference Types
JavaScript divides data types into two fundamental categories:
Primitive Types (Value Types)
- Stored directly in the variable
- Immutable (cannot be changed, only replaced)
- Compared by value
- Stored on the stack
Reference Types (Non-Primitive Types)
- Stored as references to memory locations
- Mutable (can be modified)
- Compared by reference
- Stored on the heap
Primitive Data Types
JavaScript has 7 primitive data types (ES2020+). Here's a complete breakdown:
| Type | Description | Example | typeof Result |
|---|---|---|---|
number | Numeric values (integers and floats) | 42, 3.14, NaN, Infinity | "number" |
string | Sequence of characters | "hello", 'world', `template` | "string" |
boolean | Logical true/false | true, false | "boolean" |
undefined | Variable declared but not assigned | undefined | "undefined" |
null | Intentional absence of value | null | "object" ⚠️ |
symbol | Unique, immutable identifier | Symbol('id') | "symbol" |
bigint | Arbitrary precision integers | 9007199254740991n | "bigint" |
1. Number
JavaScript uses a single number type for both integers and floating-point numbers.
let integer = 42;
let float = 3.14159;
let negative = -10;
let scientific = 1e5; // 100000
let hex = 0xff; // 255
let binary = 0b1010; // 10
let octal = 0o755; // 493
console.log(typeof integer); // "number"
console.log(typeof float); // "number"
Special Number Values:
let notANumber = NaN; // Not a Number
let infinity = Infinity; // Positive infinity
let negativeInfinity = -Infinity; // Negative infinity
console.log(NaN === NaN); // false ⚠️
console.log(isNaN(NaN)); // true
console.log(Number.isNaN(NaN)); // true (preferred)
Interview Trap: NaN !== NaN is always true. Use Number.isNaN() or isNaN() to check.
2. String
Strings are sequences of characters, immutable once created.
let single = "Single quotes";
let double = "Double quotes";
let template = `Template literals ${single}`; // ES6+
console.log(typeof single); // "string"
// String methods return new strings (immutability)
let str = "hello";
str.toUpperCase(); // Returns "HELLO", doesn't modify str
console.log(str); // "hello" (unchanged)
3. Boolean
Only two values: true and false.
let isActive = true;
let isComplete = false;
console.log(typeof isActive); // "boolean"
// Truthy and falsy values
if (0) {
} // falsy
if (1) {
} // truthy
if ("") {
} // falsy
if ("hello") {
} // truthy
if (null) {
} // falsy
if (undefined) {
} // falsy
4. Undefined
A variable that has been declared but not assigned a value.
let x;
console.log(x); // undefined
console.log(typeof x); // "undefined"
// Undefined vs not declared
let y;
console.log(y); // undefined
// console.log(z); // ReferenceError: z is not defined
5. Null
Represents the intentional absence of any value. This is a famous JavaScript quirk:
let empty = null;
console.log(typeof empty); // "object" ⚠️ (BUG in JavaScript!)
console.log(null === null); // true
console.log(null == undefined); // true (loose equality)
console.log(null === undefined); // false (strict equality)
Interview Trap: typeof null returns "object" - this is a known bug in JavaScript that can't be fixed due to backward compatibility.
6. Symbol
Introduced in ES6, symbols are unique and immutable identifiers.
let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false (always unique)
// Global symbol registry
let globalId = Symbol.for("id");
let sameGlobalId = Symbol.for("id");
console.log(globalId === sameGlobalId); // true
console.log(typeof id1); // "symbol"
7. BigInt
Introduced in ES2020, for integers larger than Number.MAX_SAFE_INTEGER.
let bigNumber = 9007199254740991n; // Note the 'n' suffix
let anotherBig = BigInt(9007199254740991);
console.log(typeof bigNumber); // "bigint"
// Cannot mix with regular numbers
// let sum = bigNumber + 1; // TypeError
let sum = bigNumber + 1n; // OK
Reference Data Types (Objects)
Everything that's not a primitive is an object (or behaves like one).
Objects
let person = {
name: "John",
age: 30,
};
console.log(typeof person); // "object"
Arrays
Arrays are objects with numeric indices.
let fruits = ["apple", "banana", "orange"];
console.log(typeof fruits); // "object" ⚠️
// Check if array
console.log(Array.isArray(fruits)); // true (preferred)
console.log(fruits instanceof Array); // true
Interview Trap: typeof [] returns "object", not "array". Use Array.isArray().
Functions
Functions are first-class objects in JavaScript.
function greet() {
return "Hello";
}
console.log(typeof greet); // "function"
Dates, RegExp, and More
let date = new Date();
let regex = /pattern/;
let error = new Error("message");
console.log(typeof date); // "object"
console.log(typeof regex); // "object"
console.log(typeof error); // "object"
Memory Behavior: Stack vs Heap
Understanding where data is stored is crucial for understanding JavaScript's behavior.
Stack (Primitive Types)
The stack is fast, limited memory where primitive values are stored directly.
let a = 10;
let b = a; // Copy of value
b = 20;
console.log(a); // 10 (unchanged)
console.log(b); // 20
What happens:
ais stored on the stack with value10b = acreates a copy of the value- Changing
bdoesn't affecta
Heap (Reference Types)
The heap is larger, slower memory where objects are stored. Variables hold references (pointers) to heap locations.
let obj1 = { value: 10 };
let obj2 = obj1; // Copy of reference, not value!
obj2.value = 20;
console.log(obj1.value); // 20 ⚠️ (changed!)
console.log(obj2.value); // 20
What happens:
obj1is stored on the stack, pointing to an object on the heapobj2 = obj1copies the reference, not the object- Both variables point to the same object on the heap
- Modifying through either variable affects the same object
Visual Representation:
// Stack Heap
// a: 10
// b: 20
// Stack Heap
// obj1: [ref] ──→ { value: 20 }
// obj2: [ref] ──┘
Pass-by-Value vs Pass-by-Reference
JavaScript is always pass-by-value, but the "value" for objects is a reference.
Primitive Types: Pass-by-Value
function changeValue(x) {
x = 20; // Changes local copy
}
let num = 10;
changeValue(num);
console.log(num); // 10 (unchanged)
Reference Types: Pass-by-Value (of Reference)
function changeObject(obj) {
//obj receives a copy of the reference, Both(obj and myObj) point to the same object
obj.value = 20; // Modifies the object
obj = { value: 30 }; // Reassigns local reference
}
let myObj = { value: 10 };
changeObject(myObj);
console.log(myObj.value); // 20 (modified, not 30!)
Why obj.value changed but obj didn't:
obj.value = 20modifies the shared objectobj = { value: 30 }only reassigns the local reference- The original
myObjstill points to the original object
More Examples
// Primitive: Value copied
let a = 5;
let b = a;
b = 10;
console.log(a, b); // 5, 10
// Object: Reference copied
let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2.push(4);
console.log(arr1, arr2); // [1,2,3,4], [1,2,3,4] (same array!)
// Creating a copy
let arr3 = [...arr1]; // Shallow copy
arr3.push(5);
console.log(arr1, arr3); // [1,2,3,4], [1,2,3,4,5] (different arrays)
Common Interview Trap Questions
Trap 1: typeof null
console.log(typeof null); // "object" ⚠️
// Correct way to check for null
let value = null;
if (value === null) {
console.log("It's null");
}
// Or use nullish coalescing
let result = value ?? "default";
Why: This is a bug in JavaScript from the first implementation. It can't be fixed without breaking existing code.
Trap 2: Object Comparison
let obj1 = { name: "John" };
let obj2 = { name: "John" };
let obj3 = obj1;
console.log(obj1 === obj2); // false ⚠️ (different references)
console.log(obj1 === obj3); // true (same reference)
// Deep comparison needed
function deepEqual(a, b) {
return JSON.stringify(a) === JSON.stringify(b);
}
console.log(deepEqual(obj1, obj2)); // true (but has limitations)
Why: Objects are compared by reference, not by value.
Trap 3: Array Type Checking
let arr = [1, 2, 3];
console.log(typeof arr); // "object" ⚠️
// Wrong way
if (typeof arr === "array") {
} // Never true!
// Correct ways
if (Array.isArray(arr)) {
} // ✅ Preferred
if (arr instanceof Array) {
} // ✅ Also works
Trap 4: NaN Comparison
let result = NaN;
console.log(result === NaN); // false ⚠️
console.log(result == NaN); // false ⚠️
// Correct ways
console.log(Number.isNaN(result)); // true ✅ (preferred)
console.log(isNaN(result)); // true (but has quirks)
Why: NaN is the only value that is not equal to itself.
Trap 5: Type Coercion
console.log([] == false); // true ⚠️
console.log([] === false); // false
console.log("5" == 5); // true ⚠️
console.log("5" === 5); // false
// Always use === for strict equality
Trap 6: Mutable Primitives (Wrapper Objects)
let str = "hello";
str.property = "value";
console.log(str.property); // undefined ⚠️
// Why: Primitives are immutable
// When you access a property, JS creates a temporary wrapper object
Real Interview Questions with Answers
Q1: What's the difference between primitive and reference types?
Answer:
- Primitive types are stored directly in variables, immutable, compared by value, and stored on the stack. Examples:
number,string,boolean,null,undefined,symbol,bigint. - Reference types are stored as references to memory locations, mutable, compared by reference, and stored on the heap. Examples:
object,array,function,Date,RegExp.
Q2: What will this code output?
let a = { x: 1 };
let b = a;
b.x = 2;
console.log(a.x);
Answer: 2
Explanation: b holds a reference to the same object as a. Modifying b.x changes the shared object, so a.x is also 2.
Q3: What's the output of typeof null and why?
Answer: "object"
Explanation: This is a known bug in JavaScript from the first implementation. The typeof operator incorrectly returns "object" for null. To check for null, use strict equality: value === null.
Q4: How do you check if a variable is an array?
Answer:
Array.isArray(variable); // ✅ Preferred
variable instanceof Array; // ✅ Also works
typeof variable === "array"; // ❌ Never works (typeof returns "object")
Q5: What's the difference between == and ===?
Answer:
==(loose equality) performs type coercion before comparison===(strict equality) compares both value and type without coercion
Examples:
"5" == 5; // true (coercion)
"5" === 5; // false (different types)
null == undefined; // true
null === undefined; // false
Q6: What will this code output?
let x = NaN;
console.log(x === NaN);
console.log(Number.isNaN(x));
Answer:
false;
true;
Explanation: NaN is the only value that is not equal to itself. Use Number.isNaN() or isNaN() to check for NaN.
Q7: Explain pass-by-value vs pass-by-reference in JavaScript.
Answer: JavaScript is always pass-by-value. For primitives, the value itself is passed. For objects, the value passed is a reference (pointer) to the object. This means:
- Primitive parameters are independent copies
- Object parameters share the same reference, so mutations are visible to the caller
Q8: What's the output?
function test(obj) {
obj = { value: 20 };
}
let myObj = { value: 10 };
test(myObj);
console.log(myObj.value);
Answer: 10
Explanation: Reassigning obj inside the function only changes the local reference. The original myObj still points to { value: 10 }.
Q9: How many primitive types are in JavaScript?
Answer: 7 primitive types:
numberstringbooleanundefinednullsymbolbigint
Q10: What's the difference between undefined and null?
Answer:
undefined: Variable declared but not assigned, or property doesn't existnull: Intentional absence of value (explicitly set)
let x; // undefined
let y = null; // null (intentional)
console.log(x == null); // true (loose equality)
console.log(x === null); // false (strict equality)
Type Checking Best Practices
Use Strict Equality (===)
// ❌ Avoid
if (value == 5) {
}
// ✅ Prefer
if (value === 5) {
}
Check for null/undefined
// ✅ Explicit checks
if (value === null) {
}
if (value === undefined) {
}
if (value == null) {
} // Checks both null and undefined
// ✅ Modern approach
if (value == null) {
} // nullish check
let result = value ?? "default"; // nullish coalescing
Array Checking
// ✅ Always use
if (Array.isArray(value)) {
}
// ❌ Never use
if (typeof value === "array") {
} // Never true!
NaN Checking
// ✅ Preferred
if (Number.isNaN(value)) {
}
// ⚠️ Works but has quirks
if (isNaN(value)) {
} // Coerces value first
Type Guards
function isString(value) {
return typeof value === "string";
}
function isNumber(value) {
return typeof value === "number" && !isNaN(value);
}
function isObject(value) {
return value !== null && typeof value === "object";
}
Key Takeaways
- JavaScript has 7 primitive types and everything else is an object
- Primitives are immutable - operations return new values
- Objects are mutable - modifications affect all references
- Memory model matters - stack for primitives, heap for objects
- Always use
===for comparisons to avoid type coercion typeof nullis"object"- it's a bug, use=== nullto checktypeof []is"object"- useArray.isArray()to check arraysNaN !== NaN- useNumber.isNaN()to check- JavaScript is pass-by-value - but object values are references
- Understand reference vs value - critical for avoiding bugs
Interview Tips
Before the Interview
- Memorize the 7 primitive types - This is often asked directly
- Practice object comparison - Know why
{} === {}isfalse - Understand
typeofquirks -nulland arrays return"object" - Know memory behavior - Stack vs heap, pass-by-value
- Practice code tracing - Be able to predict outputs
During the Interview
- Think out loud - Explain your reasoning
- Ask clarifying questions - "Should I use strict or loose equality?"
- Mention edge cases - Show you know the traps
- Use correct terminology - "reference type" not "object type"
- Draw diagrams - Visualize stack/heap when explaining
Common Follow-ups
- "How would you implement deep equality?"
- "What's the difference between
Object.is()and===?" - "How does garbage collection work with references?"
- "Explain the difference between shallow and deep copying"
Summary
JavaScript's type system is deceptively simple but full of nuances:
- 7 primitive types stored on the stack, compared by value
- Reference types stored on the heap, compared by reference
- Memory behavior determines how values are copied and compared
- Type coercion can cause unexpected behavior - always use strict equality
- Common traps like
typeof nulland array checking trip up many developers
Mastering these concepts is essential for writing robust JavaScript and acing technical interviews. Remember: understanding why something behaves a certain way is more valuable than memorizing facts.
Pro tip: When in doubt, use strict equality (
===),Array.isArray(), and explicit type checks. It's better to be explicit than to rely on JavaScript's quirky type coercion.