What are the different data types in JavaScript?
Advertisement
🧩 Scenario
Architecture Walkthrough
The Seven Primitive Types
JavaScript has seven primitive types: string, number, boolean, undefined, null, symbol, and bigint. Primitive values are immutable, meaning the value itself cannot be changed. When you reassign a variable that holds a primitive, you are replacing the reference to the old value with a reference to a new one, not modifying the original.
Primitives are compared by value. Two variables holding the same string or number are considered equal when compared with ===. undefined represents a variable that has been declared but not yet assigned a value. null is an intentional assignment that represents the absence of a value. Symbol creates a guaranteed-unique identifier useful for property keys that must not collide. BigInt handles integers larger than Number.MAX_SAFE_INTEGER (2^53 - 1).
The Object Type and Reference Behavior
Everything that is not a primitive is an object in JavaScript. This includes plain objects, arrays, functions, dates, maps, and sets. Objects are stored as references: a variable holds a pointer to the memory location where the data lives, not the data itself.
Reference comparison means two distinct object literals with identical content are not equal when compared with ===. They are separate allocations in memory. Only when two variables point to the exact same object in memory will a strict equality check return true. This distinction is critical for understanding state comparison in React, caching, and deep equality checks.
typeof and Its Known Quirks
The typeof operator returns a string describing the type of a value. For most primitives it behaves as expected. However, typeof null returns "object", which is a longstanding bug in the language that was not fixed to preserve backward compatibility. typeof for a function returns "function" even though functions are objects. And typeof for an array also returns "object", so you need Array.isArray() to reliably check for arrays.
Knowing these quirks matters because typeof is still the most common way to check types in JavaScript, and misreading its output leads to incorrect conditional branches and silent bugs.
Key Code Explained
// Primitive: comparison by value
const a = 'hello';
const b = 'hello';
console.log(a === b); // true
// Object: comparison by reference
const obj1 = { name: 'Ghazi' };
const obj2 = { name: 'Ghazi' };
console.log(obj1 === obj2); // false — different objects in memory
const obj3 = obj1;
console.log(obj1 === obj3); // true — same reference
// typeof quirks
console.log(typeof null); // "object" (historical bug)
console.log(typeof []); // "object" (not "array")
console.log(typeof function () {}); // "function"
console.log(Array.isArray([])); // true — correct way to check for arrays
// Primitives passed to functions do not mutate the original
function increment(n) {
n++;
return n;
}
let count = 5;
increment(count);
console.log(count); // still 5
// Objects passed to functions share the reference
function rename(user) {
user.name = 'Ali';
}
const person = { name: 'Ghazi' };
rename(person);
console.log(person.name); // 'Ali' — the original was mutated
The function examples demonstrate a key consequence of the primitive/reference distinction. Primitives are effectively passed by value, so changes inside a function do not affect the caller. Objects are passed by reference (technically "pass by sharing"), so mutations inside a function affect the original object.
Tradeoffs
| Aspect | Primitives | Objects (Reference Types) |
|---|---|---|
| Storage | By value, independent copy | By reference, shared pointer |
| Equality | === compares actual values | === compares memory addresses |
| Mutability | Immutable, reassignment only | Mutable, properties can change in place |
What Interviewers Actually Check
- Whether you can list all 7 primitive types without confusing the list
- Whether you know
typeof null === "object"and why it returns that - Whether you understand that arrays and functions are objects in JavaScript
- Whether you can correctly predict equality behavior for both primitives and objects
- Whether you know what
undefinedandnulleach represent and when each is appropriate - Whether you can explain pass-by-value vs pass-by-reference using a function argument example
Follow-Up Questions
- How does JavaScript's dynamic typing differ from TypeScript's type system, and what category of bugs does TypeScript prevent?
- If you need to check whether a variable is an array, what is the most reliable way and why not
typeof? - How would you write a utility function to perform deep equality comparison between two objects?
- Why does
NaN !== NaNevaluate totrue, and how do you correctly check forNaN? - In a high-volume data processing pipeline, would you prefer strings or numbers as map keys for performance, and why?
Common Candidate Mistakes
- Expecting
typeof nullto return"null"when it returns"object", which is a known language bug - Assuming two objects with identical contents are equal when compared with
=== - Confusing
undefined(declared but not assigned) withnull(intentionally empty), or using them interchangeably - Forgetting that arrays and functions are objects under the hood, causing incorrect
typeofassumptions - Not knowing that
Symbol()produces a unique value every time it is called, even with the same description string
Interview Readiness Checklist
Before you leave this question, make sure you can answer:
- Can you list all 7 primitive types from memory?
- Can you explain what
typeof nullreturns and why that is considered a historical bug? - Can you demonstrate value equality for primitives and reference equality for objects with a code example?
- Can you explain what happens when you reassign a primitive variable versus when you mutate an object property?
- Can you name a real use case for
SymbolandBigInt? - Can you explain what dynamic typing means and give an example of a type coercion pitfall?
Summary
JavaScript has seven primitive types: string, number, boolean, undefined, null, symbol, and bigint. These are immutable and compared by value. Everything else is an object, a reference type that is mutable and compared by memory address rather than content.
The practical consequences of this split appear constantly: equality checks between two objects with the same contents return false, functions that mutate object arguments affect the caller, and cloning requires explicit effort. The typeof operator is the primary tool for runtime type checking, but it has well-known quirks around null, arrays, and functions that every JavaScript developer must know.
Understanding this foundation makes the rest of JavaScript's behavior predictable. Type coercion, loose equality, state comparison in React, and the entire cloning topic all depend on knowing which types are primitives and which are references.
Is JavaScript strongly typed?
No, JavaScript is dynamically typed — variables can change type at runtime.
Advertisement
Stay Updated
Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.
Advertisement