Implement a Browser History Stack

BrowserHistory tracks visited URLs with a pointer. Implement push (truncating forward entries), back, forward, go(n) with boundary clamping, and canGoBack/canGoForward getters.

11 min read
JavaScript
Interview
Implementation
Data Structures

TABLE OF CONTENTS

Implementing a browser history stack tests class design and the edge case that makes it non-trivial: pushing a new page while you're in the middle of the history should discard all forward entries — exactly how real browsers behave.


What is a Browser History?

A browser history tracks visited URLs as a stack with a pointer. Three operations:

  • push(url) — navigate to a new URL, discarding any forward history
  • back() — move the pointer one step backward
  • forward() — move the pointer one step forward

The pointer (current index) is what makes this different from a plain stack. You're not always at the top — you can go back, then forward, or push a new page from the middle.

The critical rule: pushing from a non-top position truncates forward history. If you go Back → Back → push("/new"), the two forward entries are gone. This matches the real browser's History API.


The Problem

"Implement a BrowserHistory class with push(url), back(), forward(), and a current property. push from a non-top position should discard forward entries."

The interviewer extends:

"Add a go(n) method — go(-2) goes 2 steps back, go(1) goes 1 step forward. Add canGoBack and canGoForward boolean properties."


Thought Process

The data structure is an array with a pointer (index):

  • push: truncate array at index + 1, append new URL, advance index
  • back: index-- (bounded at 0)
  • forward: index++ (bounded at history.length - 1)
  • go(n): index = clamp(index + n, 0, length - 1)
  • current: history[index]

Use private fields (#) to prevent external mutation of the history array.


Step 1 — Base Implementation

Loading editor...


Step 2 — go(n), canGoBack, canGoForward

Loading editor...


Step 3 — Edge Cases

Loading editor...


Full Solution

Loading editor...


What Interviewers Are Testing

  • Truncation on push — the non-trivial rule: push from a non-top position discards forward entries. Missing this is the most common mistake.
  • Private fields — using # to prevent external tampering with the history array
  • go(n) generalization — implementing back and forward as go(-1) / go(1) shows you recognize the abstraction
  • Boundary clampinggo(-100) should stop at the beginning, not go negative
  • Getters for canGoBack/Forward — boolean properties computed on-demand, not stored state

Complexity

OperationTimeSpace
pushO(H) — slice to truncateO(H) total
back, forward, goO(1)O(1)

Interview Tips

  • State the truncation rule immediately — "The tricky part is that push from a non-top position discards all forward entries. I'll handle that with slice(0, index + 1) before appending."
  • Use private fields — shows modern JS knowledge and good encapsulation. "I'm using #history so nothing outside the class can corrupt the array."
  • Implement go(n) first, then delegate — cleaner than implementing back and forward independently with duplicate logic.
  • Mention the real API — "This mirrors the browser's window.history.pushState(), history.back(), history.forward(), and history.go(n)."

Related Questions


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI