JavaScript Data Types
Understand how JavaScript classifies, stores, converts, compares, and evaluates values.
1. What is a Data Type?
A data type defines the kind of value a piece of data represents, how much memory it occupies, and what mathematical or logical operations can be performed on it.
JavaScript is dynamically typed (loosely typed). You do not declare variable types explicitly (like int or String in Java/C++). Instead, types are attached to the underlying value at runtime.
let value = 42; // Currently holding a Number
value = "Hello"; // Now holding a String
value = true; // Now holding a Boolean
๐ก Important Distinction: Variables vs Values
โข Variables do not have fixed types; they are simply labeled containers that can point to different values over time.
โข Values have concrete types (e.g. the literal 42 is always a Number; "Hello" is always a String).
2. The 7 Primitive Types
JavaScript has 7 primitive data types. Primitives hold raw values directly in Call Stack memory and are immutable.
3. Primitive vs Reference Types (Memory Model)
How JavaScript values live and behave in memory is the single most tested concept in technical interviews:
Primitive Types (Stack Memory)
- Stored directly in the fast Call Stack
- Fixed memory size, immutable in place
- Copied by value (copying creates an independent value)
let x = 10;
let y = x; // independent copy
y = 20;
console.log(x); // 10 (untouched)
console.log(y); // 20
Reference Types (Heap Memory)
- Objects, Arrays, Functions stored in the flexible Heap
- Dynamic expandable memory size
- Copied by reference (both point to the same memory address)
let userA = { score: 100 };
let userB = userA; // copies pointer
userB.score = 999;
console.log(userA.score); // 999 (altered!)
console.log(userB.score); // 999
๐ก Mental Model: Stack vs Heap Memory
โข Primitives (Value Copy): Like photocopying a document. If you draw a smiley face on your copy (y), the original piece of paper (x) remains completely unchanged.
โข Reference Types (Pointer Copy): Like sharing a Google Doc link. If anyone edits the document online (userB.score = 999), everyone with the link sees the modification immediately!
4. The typeof Operator
The typeof unary operator returns a string indicating the type of the unevaluated operand.
| Category | Data Type | typeof Return |
Examples & Literals | Memory Storage |
|---|---|---|---|---|
| Primitive | Number | "number" |
42, 3.14, NaN, Infinity |
Call Stack (Fixed 8 Bytes) |
| Primitive | String | "string" |
"Hello", 'JS', `Template` |
Call Stack (Immutable) |
| Primitive | Boolean | "boolean" |
true, false |
Call Stack (1 Byte) |
| Primitive | Undefined | "undefined" |
undefined |
Call Stack |
| Primitive | Null | "object" (Legacy Bug) |
null |
Call Stack |
| Primitive | BigInt | "bigint" |
9007199254740991n, 100n |
Call Stack (Arbitrary Size) |
| Primitive | Symbol | "symbol" |
Symbol("id"), Symbol.for("key") |
Call Stack (Unique Token) |
| Reference | Object | "object" |
{ name: "Alex", score: 100 } |
Heap (Stack holds pointer) |
| Reference | Array | "object" |
[1, 2, 3], ["A", "B"] |
Heap (Specialized Object) |
| Reference | Function | "function" |
function() {}, () => {} |
Heap (Callable Object) |
5. The typeof null Quirk (Interview Classic)
โ ๏ธ The 1995 Legacy Bug: typeof null === "object"
typeof null returns "object". This is a famous bug from the first release of JavaScript in 1995.
In the original C-based JavaScript engine, values were represented with type tags stored in the lowest bits. Object type tags were 000. Since null was represented as the NULL pointer (0x00), its type tag was 000, causing typeof to wrongly return "object".
How to correctly check for null?
const isNull = (val) => val === null; // โ
Strict equality
6. Special Numbers: NaN, Infinity, and -Infinity
JavaScript includes three special numeric values within the number data type:
NaN
"Not-a-Number". Produced by invalid math operations (e.g. 0 / 0, "abc" * 2, Math.sqrt(-1)).
Infinity
Positive infinite limit. Produced when a calculation exceeds the maximum limit (e.g. 1 / 0, 1e308 * 2).
-Infinity
Negative infinite limit. Produced by dividing negative numbers by zero (e.g. -1 / 0, -Infinity).
Why NaN is unique in JavaScript:
NaN is the only value in JavaScript that is not equal to itself:
console.log(NaN === NaN); // false โ
// How to reliably check for NaN:
console.log(Number.isNaN(NaN)); // true โ
(Strict, reliable)
console.log(Object.is(NaN, NaN)); // true โ
(ES6 SameValue equality)
// โ ๏ธ Warning: The global isNaN() coerces values before checking:
console.log(isNaN("hello")); // true (coerces "hello" -> NaN)
console.log(Number.isNaN("hello")); // false (does NOT coerce, strictly checks)
false true true true false
7. Type Conversion: Explicit vs Implicit Coercion
Type conversion converts a value from one data type to another. It occurs in two ways:
A. Explicit Type Conversion (Intentional & Predictable)
Developers manually convert types using built-in wrapper functions:
String Conversion: String(val)
Converts any value directly into its textual string representation:
String(123); // "123"
String(true); // "true"
String(null); // "null"
String(undefined); // "undefined"
String([1, 2]); // "1,2"
Number Conversion: Number(val)
Parses numeric values. Empty strings become 0; undefined becomes NaN:
Number("42"); // 42
Number(" 123 "); // 123
Number(""); // 0
Number("abc"); // NaN
Number(true); // 1 (false -> 0)
Number(null); // 0 (undefined -> NaN)
Boolean Conversion: Boolean(val)
Evaluates truthiness. Only the 8 falsy values convert to false:
Boolean(1); // true (0 -> false)
Boolean("Hello"); // true ("" -> false)
Boolean([]); // true (objects truthy)
Boolean({}); // true
Boolean(null); // false
Boolean(undefined);// false
B. Implicit Coercion (Automatic Runtime Coercion)
JavaScript automatically converts types behind the scenes when operators encounter mismatched types:
Plus (+) Operator (String Bias)
If any operand is a string, + performs string concatenation:
"5" + 2; // "52"
1 + "2" + 3; // "123"
1 + 2 + "3"; // "33" (1+2=3, "3"+"3"="33")
"Hi " + true; // "Hi true"
Math Operators (-, *, /, %)
Arithmetic operators strictly coerce string operands into Numbers:
"5" - 2; // 3
"10" * "2"; // 20
"10" / "2"; // 5
"abc" - 2; // NaN
Equality Comparison (== vs ===)
== coerces types before checking; === requires matching type & value:
5 == "5"; // true (coerced)
5 === "5"; // false (different types)
null == undefined; // true (spec exception)
null === undefined;// false
8. Truthy and Falsy Values
In JavaScript, every value is inherently either truthy or falsy when evaluated inside a boolean context (such as an if condition, logical operator, or Boolean() call).
๐ The Golden Rule of Truthy & Falsy
There are only 8 exact falsy values in JavaScript. Everything else without exception is TRUTHY (including empty objects {}, empty arrays [], and negative numbers like -1)!
| Falsy Value | Type | Description |
|---|---|---|
false | Boolean | The boolean literal false |
0 | Number | The number zero |
-0 | Number | Negative zero |
0n | BigInt | BigInt zero |
"", '', `` | String | Empty strings (zero characters) |
null | Null | The null primitive |
undefined | Undefined | The undefined primitive |
NaN | Number | Not-a-Number |
9. Mutability: Primitives vs Objects
Understanding mutability prevents accidental state corruption bugs:
- Primitives are Immutable: Once a primitive value is created in memory, its character sequence or numeric value can never be altered. String methods like
.toUpperCase()or.trim()return a brand-new string; they never modify the original. - Objects are Mutable: Object keys and array elements can be added, updated, or deleted in place without changing the memory reference address.
// Primitive Immutability
let word = "hello";
word[0] = "H"; // Silently fails (or throws in strict mode)
console.log(word); // "hello" (Unchanged!)
let upperWord = word.toUpperCase(); // Creates a brand-new string
console.log(word); // "hello" (Original intact)
console.log(upperWord); // "HELLO"
// Object Mutability
const user = { name: "Alex" };
user.name = "Sam"; // Mutates object in place
user.role = "Admin";
console.log(user); // { name: 'Sam', role: 'Admin' }
10. ๐ฏ Placement & Interview Quiz (8 Output Traps)
Test your mastery of data types, coercion, and evaluation traps commonly asked in technical screening interviews. Answer each question one by one:
11. Common Data Type Mistakes & How to Avoid Them
Using == Instead of ===
5 == "5" allows hidden implicit coercion. Always use === for type-safe comparisons.
Assuming isNaN() is Safe
Global isNaN("hello") returns true even though "hello" is a string. Use Number.isNaN() instead.
Checking typeof null === "null"
typeof null returns "object". Always check with val === null.
Assuming Empty Arrays are Falsy
Boolean([]) is true! To check if an array is empty, check arr.length === 0.
12. Quick Revision Reference Table
| Type Name | Category | typeof Output | Memory Location | Example Literals |
|---|---|---|---|---|
number | Primitive | "number" | Call Stack | 42, 3.14, NaN, Infinity |
string | Primitive | "string" | Call Stack | "Hello", 'world' |
boolean | Primitive | "boolean" | Call Stack | true, false |
undefined | Primitive | "undefined" | Call Stack | undefined |
null | Primitive | "object" โ ๏ธ | Call Stack | null |
bigint | Primitive | "bigint" | Call Stack | 100n, 9007199254740991n |
symbol | Primitive | "symbol" | Call Stack | Symbol('id') |
object | Reference | "object" | Heap Memory | { a: 1 }, [1, 2] |
function | Reference | "function" | Heap Memory | () => {}, function() {} |
13. Interactive Practice Challenge
๐ฏ Coding Challenge: Robust Type Analyzer
Write a function analyzeValue(val) that takes any value and correctly returns:
โข "null" if the value is null (bypassing the typeof bug)
โข "NaN" if the value is NaN
โข "array" if the value is an Array
โข Otherwise returns standard typeof val