Build the core mental models behind programming through data representation, algorithms, complexity, data structures, recursion, memory, operating systems, networking, databases, and concurrency.
Explain how computers represent and process information
Analyze basic algorithm time and space complexity
Choose appropriate foundational data structures
Understand recursion, stacks, queues, trees, and hash tables
Describe fundamental memory, operating system, networking, and database concepts
Reason about concurrency and parallel execution
Computers ultimately represent information using binary states. Numbers, characters, images, instructions, and other data are encoded as patterns of bits.
A bit represents one binary value. Eight bits form a byte, and larger values are represented using sequences of bytes interpreted according to a particular encoding.
A bit represents 0 or 1
Eight bits make one byte
The meaning of bytes depends on their encoding and interpretation
const binary = "101101";
const decimal = Number.parseInt(binary, 2);
console.log(decimal);
// 45
console.log(decimal.toString(2));
// "101101"An algorithm is a finite sequence of steps for solving a problem or transforming data. The same problem can often be solved by many different algorithms.
Good algorithm design considers correctness, clarity, computational cost, and the constraints of the input.
An algorithm describes a procedure for solving a problem
Correctness comes before optimization
Different algorithms can have very different performance characteristics
function findMaximum(values) {
if (values.length === 0) {
return undefined;
}
let maximum = values[0];
for (const value of values) {
if (value > maximum) {
maximum = value;
}
}
return maximum;
}
console.log(findMaximum([4, 12, 7, 2]));
// 12Complexity describes how an algorithm's resource requirements grow as input size increases. Big O notation commonly describes an upper-bound growth rate.
Complexity focuses on growth rather than exact execution time, allowing algorithms to be compared independently of a particular machine.
O(1) represents constant growth
O(n) commonly represents linear growth
O(log n) commonly appears when the problem space is repeatedly divided
const users = ["Ada", "Grace", "Linus"];
// O(1) by index
const firstUser = users[0];
// O(n) in the worst case
function containsUser(name) {
for (const user of users) {
if (user === name) {
return true;
}
}
return false;
}Arrays store ordered collections and provide efficient indexed access. Their elements are conceptually arranged in a sequence that supports direct access by position.
Linked lists represent sequences through nodes containing values and references to other nodes. They trade direct indexing for flexible insertion and removal when the relevant node is already known.
Arrays provide efficient indexed access
Linked lists connect values through node references
Data structure choice depends on the operations an application performs most often
class ListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}
const third = new ListNode("C");
const second = new ListNode("B", third);
const first = new ListNode("A", second);
console.log(first.next.value);
// "B"A stack follows last-in, first-out behavior. The most recently added item is the first item removed.
A queue follows first-in, first-out behavior. The earliest added item is normally the first item removed.
Stacks use LIFO ordering
Queues use FIFO ordering
Call stacks, undo systems, task scheduling, and breadth-first search use these ideas
const history = [];
history.push("home");
history.push("courses");
history.push("react");
const current = history.pop();
console.log(current);
// "react"
console.log(history);
// ["home", "courses"]Hash tables associate keys with values by using a hash function to determine where data should be stored.
With a suitable implementation and distribution of keys, insertion, lookup, and deletion commonly have average-case constant-time behavior.
Hash tables map keys to values
Collisions occur when multiple keys map to the same storage location
JavaScript Map and many dictionary structures use hash-table-like concepts
const usersById = new Map();
usersById.set("u1", {
name: "Ada",
role: "admin",
});
usersById.set("u2", {
name: "Grace",
role: "user",
});
console.log(usersById.get("u1"));
// { name: "Ada", role: "admin" }Recursion occurs when a function solves a problem by calling itself with a smaller version of that problem.
A recursive algorithm needs a base case that stops further calls. Without a reachable base case, recursion continues until available call-stack space is exhausted.
Define a base case
Move each recursive call toward the base case
Understand that recursive calls consume call-stack frames
function factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(5));
// 120Trees represent hierarchical relationships using nodes connected through parent-child relationships. File systems, DOM structures, syntax trees, and search indexes commonly use tree-like structures.
Depth-first traversal explores a branch before returning, while breadth-first traversal explores nodes level by level.
Trees model hierarchical information
Depth-first search commonly uses recursion or a stack
Breadth-first search commonly uses a queue
function depthFirst(node) {
if (!node) {
return;
}
console.log(node.value);
depthFirst(node.left);
depthFirst(node.right);
}
const tree = {
value: "A",
left: {
value: "B",
left: null,
right: null,
},
right: {
value: "C",
left: null,
right: null,
},
};
depthFirst(tree);Searching algorithms locate values in collections, while sorting algorithms arrange values according to an ordering rule.
Binary search can achieve logarithmic search complexity when operating on sorted data by repeatedly eliminating half of the remaining search space.
Linear search works without sorted input
Binary search requires an ordered search space
Sorting can make later operations more efficient
function binarySearch(values, target) {
let left = 0;
let right = values.length - 1;
while (left <= right) {
const middle = Math.floor((left + right) / 2);
const value = values[middle];
if (value === target) {
return middle;
}
if (value < target) {
left = middle + 1;
} else {
right = middle - 1;
}
}
return -1;
}
console.log(binarySearch([2, 5, 8, 12, 20], 12));
// 3Programs need memory for instructions, function calls, variables, objects, and runtime state. Languages and runtimes organize and manage this memory in different ways.
A call stack tracks active function calls. Dynamically allocated objects commonly live in another region of memory managed by the runtime, often described conceptually as the heap.
The call stack tracks active function execution
Objects may outlive the function that created them
Garbage-collected runtimes reclaim unreachable memory automatically
function third() {
return "done";
}
function second() {
return third();
}
function first() {
return second();
}
console.log(first());
// Conceptually, calls are pushed onto
// the call stack and removed as they return.An operating system manages hardware resources and provides abstractions for running programs, files, networking, memory, devices, and security.
A process is an executing program with its own runtime resources. A process can contain one or more threads of execution.
Operating systems coordinate hardware and software resources
A process represents a running program
Threads provide execution paths within a process
console.log({
processId: process.pid,
platform: process.platform,
architecture: process.arch,
uptimeSeconds: process.uptime(),
});Computer networks allow machines to exchange data using agreed protocols. IP addresses identify network interfaces, while ports identify application endpoints on a machine.
Applications commonly use protocols such as TCP for reliable ordered byte streams and HTTP for web request-response communication.
IP addresses identify network locations
Ports identify application endpoints
HTTP operates as an application-layer protocol
const url = new URL(
"https://api.example.com:443/users?page=2",
);
console.log(url.protocol); // "https:"
console.log(url.hostname); // "api.example.com"
console.log(url.port); // ""
console.log(url.pathname); // "/users"
console.log(url.search); // "?page=2"Databases provide structured ways to persist and retrieve information. Relational databases organize information into tables connected through keys and relationships.
Indexes can improve lookup performance by maintaining additional structures optimized for particular access patterns, though indexes also require storage and maintenance.
Primary keys uniquely identify records
Foreign keys represent relationships between records
Indexes trade additional storage and write cost for faster retrieval
SELECT
users.name,
orders.id,
orders.total
FROM users
JOIN orders
ON orders.user_id = users.id
WHERE users.id = 42
ORDER BY orders.created_at DESC;Concurrency describes systems that make progress on multiple tasks during overlapping periods of time. Parallelism means multiple operations are literally executing at the same instant.
Shared mutable state can create race conditions when multiple execution paths interact without appropriate coordination.
Concurrency and parallelism are related but different concepts
Shared mutable state can create race conditions
Coordination mechanisms protect critical operations
async function loadDashboard() {
const profilePromise = fetch("/api/profile");
const activityPromise = fetch("/api/activity");
const [profileResponse, activityResponse] =
await Promise.all([
profilePromise,
activityPromise,
]);
return {
profile: await profileResponse.json(),
activity: await activityResponse.json(),
};
}