Data Types & Type System
Master JavaScript's dynamic type system. Understand the distinction between Primitive and Reference types, memory allocation, and the technical edge cases of high-performance JS.
The Type System Philosophy
JavaScript is dynamically typed and weakly typed. Unlike C++ or Java, variables are not bound to a specific type; instead, types are associated with the values they hold. This provides immense flexibility but requires a deep understanding of how the engine manages these transitions.
let data = 42; // Initially a Number
data = 'Hello'; // Reassigned to a String
data = true; // Reassigned to a Boolean
data = { name: 'Alice' }; // Reassigned to an Object
// JavaScript engines handle this dynamic transition at runtime.Primitive Types (Stored by Value)
Primitives are the simplest data types. They are immutable (the value itself cannot change) and are stored directly in the "Stack" memory for fast access.
1. Number
Unlike other languages with int, float, and double, JavaScript has only one type for numbers: 64-bit binary floating-point (IEEE 754).
// Integers and Floating-point
let age = 25;
let pi = 3.14159;
// Special numeric values
let infinity = Infinity;
let notANumber = NaN; // Result of invalid math (e.g., 'abc' / 2)
// Precise NaN checking
console.log(Number.isNaN(NaN)); // true
console.log(Number.isNaN('hello')); // false (strict and accurate)Because JS uses binary math to represent decimal fractions, some calculations (like 0.1 + 0.2) yield unexpected results.
// The IEEE 754 Problem
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // false
// Engineering Solution: Use epsilon or rounding
const isCloseEnough = Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON;
console.log(isCloseEnough); // true2. String
Strings are sequences of characters. In modern JS, Template Literals(backticks) are the preferred way to handle dynamic text and multi-line strings.
// Template Literals (ES6+)
const user = 'Alice';
const greeting = `Hello, ${user}!
The date is ${new Date().toLocaleDateString()}.`;
// String methods (immutable)
const tech = 'JavaScript';
console.log(tech.slice(0, 4)); // "Java"
console.log(tech.toUpperCase()); // "JAVASCRIPT"3. Boolean
Logical values: true or false. Crucial for control flow logic and conditional rendering in frameworks like React.
4. Undefined & Null
These represent "nothingness" but carry different semantic meanings in a codebase.
let a; // undefined (automatic: "I don't know what this is")
let b = null; // null (manual: "I explicitly say this is empty")
console.log(typeof a); // "undefined"
console.log(typeof b); // "object" (Historical bug alert!)
console.log(a == b); // true (Loose equality)
console.log(a === b); // false (Strict equality)5. BigInt (ES2020)
Used for integers larger than Number.MAX_SAFE_INTEGER. This is critical for financial applications or high-precision cryptography.
// For numbers larger than 2^53 - 1
const huge = 9007199254740991n;
const anotherHuge = BigInt("9007199254740991000");
const sum = huge + 10n; // ✅ Must use 'n' suffix
// const invalid = huge + 10; // ⌠Error: Cannot mix types6. Symbol (ES6)
Symbols generate unique identifiers. They are primarily used to add hidden metadata to objects without clashing with existing keys.
// Unique identifiers
const ID_KEY = Symbol('id');
const user = {
name: 'Alice',
[ID_KEY]: 12345
};
console.log(user[ID_KEY]); // 12345
// Symbols are invisible to Object.keys() and for...in loopsReference Types (Objects)
Everything else in JavaScript is an Object. Unlike primitives, objects are complex structures stored in the "Heap" memory. When you assign an object to a variable, you are storing a pointer to that memory location.
// Reference Types
const profile = {
username: 'dev_hero',
skills: ['JS', 'React']
};
const colors = ['red', 'green']; // Arrays are objects
console.log(typeof colors); // "object"Arrays and Functions are technically objects under the hood! You can verify this by checkingtypeof someFunction which returns "function" (a callable object).Memory Management: Stack vs Heap
Understanding the memory model is what separates junior developers from senior engineers. It explains how data is shared across your application.
Pass by Value (Stack)
Simple primitives are copied entirely. Changing the copy does not affect the original.
// Primitives (Stack Memory)
let x = 10;
let y = x; // Copying the actual value
y = 20;
console.log(x); // 10 (Remains unchanged)Pass by Reference (Heap)
Objects share a memory address. Modifying the object through one variable will reflect across all variables pointing to that same object.
// Reference Types (Heap Memory)
let obj1 = { val: 10 };
let obj2 = obj1; // Copying the reference (memory address)
obj2.val = 20;
console.log(obj1.val); // 20 (Changed via reference!)Professional Type Checking
Because of JavaScript's dynamic nature, verifying types is essential for bug prevention. The typeof operator is helpful but has limitations (like for arrays and null).
| Scenario | Best Practice Approach |
|---|---|
| Basic Primitives | typeof x === 'string' / 'number' |
| Arrays | Array.isArray(x) |
| Null | x === null |
| Instance of Class | x instanceof Date / Map |
Key Takeaways:
- ✅ There are 7 Primitives + Objects.
- ✅ Primitives are immutable and stored in the Stack.
- ✅ Objects are mutable, stored in the Heap, and accessed by reference.
- ✅ Use
BigIntfor large-scale mathematical operations. - ✅ Be cautious of
0.1 + 0.2floating-point precision issues. - ✅ Use
Array.isArray()instead oftypeoffor checking arrays.