Crux Read real JavaScript snippets — a reversal pointer bug, a delete-by-value bug, a broken array queue, and a monotonic-stack pattern — and pick the highest-leverage diagnosis or fix.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 14 min
Pointer bugs in linked-list code do not crash loudly — they corrupt the structure quietly. Read each snippet, trace the pointers in your head, and pick what a senior engineer would flag first.
Goal
Practise the loop you run on every list/stack/queue review: read the pointer moves, predict where a node is lost or a complexity claim is wrong, and name the precise fix.
Snippet 1 — the reversal that loses the tail
function reverse(head) { let prev = null; let current = head; while (current !== null) { current.next = prev; // reverse the pointer prev = current; current = current.next; // advance } return prev;}
Quiz
Completed
What happens when this runs on [10] -> [20] -> [30]?
Heads-up It cannot: the line current = current.next reads the pointer you just overwrote. On node 10, current.next is now null (prev), so the loop ends after one node and 20, 30 are dropped.
Heads-up The first pointer is mutated (10.next becomes null), so the list is already corrupted, not unchanged. The traversal also halts early because the advance reads the overwritten pointer.
Heads-up No exception is thrown — current becomes null cleanly and the loop just exits early. The bug is silent truncation, which is worse than a crash.
Snippet 2 — delete by value without a sentinel
function deleteValue(head, target) { let current = head; while (current !== null) { if (current.value === target) { current = current.next; // "remove" it } current = current.next; } return head;}
Quiz
Completed
Does this delete the target node from the list?
Heads-up current is a local variable. Moving it does not alter the list's pointers. To unlink a node you must change the previous node's next field, not a local copy of the reference.
Heads-up It deletes nothing anywhere, head or middle. No predecessor pointer is ever rewritten, so no node is unlinked at any position.
Heads-up Nothing is deleted, so there is nothing to leak. The fix is to track prev and set prev.next = current.next; a sentinel head removes the head special case.
The queue is correct but a load test shows it crawling. What is the cause and the highest-leverage fix?
Heads-up push is amortized O(1) and is fine. unshift is O(n) like shift and would make enqueue slow too. The defect is shift on dequeue, not push.
Heads-up Capacity does not fix the per-dequeue reindex cost. Even a huge array pays O(n) on each shift. You must stop reindexing — use pointers/indices instead.
Heads-up They can — a circular buffer over an array with front/rear indices is a fine O(1) queue. The problem is specifically the shift call, not the array.
Snippet 4 — the monotonic-stack pattern
function dailyWarmerWait(temps) { const result = new Array(temps.length).fill(0); const stack = []; // indices, decreasing temps for (let i = 0; i < temps.length; i++) { while (stack.length && temps[i] > temps[stack[stack.length - 1]]) { const j = stack.pop(); result[j] = i - j; // days until a warmer temperature } stack.push(i); } return result;}
Quiz
Completed
For temps [73, 74, 75, 71, 69, 72, 76, 73], what does this return and what is its complexity?
Heads-up It records the gap in days (i - j), not the temperature value. The pattern is next-greater by distance, not next-greater value — read what is written into result[j].
Heads-up The nested while does not make it quadratic. Each index is popped at most once across the whole run, so total pops are bounded by n: the algorithm is O(n) amortized.
Heads-up 0 is correct exactly for indices that are never popped — days with no warmer future day (here the last 76 and 73). Every popped index gets its real gap written.
Recap
Every list/stack/queue bug is read in the pointers and the cost model. Reversal must save the successor before overwriting current.next, or it loses the tail. Deletion must repoint the predecessor — moving a local reference changes nothing — and a sentinel head erases the head special case. A FIFO queue must never dequeue with shift; use head/tail pointers or a circular buffer for O(1). And the monotonic stack stays linear because each index is pushed once and popped at most once, regardless of the inner while loop.