Skip to Content
Course content

168: Implementing a Linked List in JavaScript

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've always found that the best way to understand a Linked List isn't by looking at a diagram of boxes and arrows, but by trying to solve a problem where a standard JavaScript array actually gets in the way. Let's imagine we're building a music playlist. We want to be able to add songs to the beginning or the end, and maybe shuffle things around later.

Trying to wing it with objects

At first, I might just think: "I'll just use an object to represent a song, and another object for the next song." Let's see what happens if I do that manually.

const song1 = { title: "Bohemian Rhapsody", next: null };
const song2 = { title: "Stairway to Heaven", next: null };
const song3 = { title: "Hotel California", next: null };

// Now I'll manually link them
song1.next = song2;
song2.next = song3;

console.log(song1);

This works! If I have song1, I can find song2 via the next property. But honestly, this is a nightmare to maintain. If I want to add a fourth song, I have to manually find the last song in the chain and update its next property. That's not scalable. I'm basically doing the work the computer should be doing.

Creating a Blueprint for the Node

To clean this up, I need a consistent structure. In linked list terminology, these song objects are called "Nodes." Let's wrap this in a class so I don't have to remember to add the next property every single time I create a song.

class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }
}

const nodeA = new Node("Bohemian Rhapsody");
const nodeB = new Node("Stairway to Heaven");
nodeA.next = nodeB;

Better. But I'm still managing the links myself. I need a "manager" for these nodes—something that knows where the list starts and provides methods to manipulate it without me touching the next pointers directly.

The Manager Class and the 'Head'

I'll create a Playlist class. The most important part here is the head. The head is just a reference to the first node. If I lose the head, I lose the entire list because there's no way to "go back" to the start.

class Playlist {
    constructor() {
        this.head = null;
    }

    // Let's try adding a song to the start
    prepend(songTitle) {
        const newNode = new Node(songTitle);
        newNode.next = this.head;
        this.head = newNode;
    }
}

Wait, let me trace that logic in my head. If the list is empty, this.head is null. newNode.next becomes null, and this.head becomes the new node. If the list already has songs, the new node points to the current first song, and then becomes the new head. It's a seamless handoff. This is actually way faster than Array.unshift() because I'm not re-indexing every other element in the list.

Walking the Chain

Prepending is easy, but what if I want to add a song to the end? I can't just jump to the end because I don't have a reference to the last node—I only know where the head is. I have to "traverse" the list.

I'll try implementing an append method. I'll use a while loop to keep moving to the next node until I hit null.

append(songTitle) {
    const newNode = new Node(songTitle);

    if (!this.head) {
        this.head = newNode;
        return;
    }

    let current = this.head;
    while (current.next !== null) {
        current = current.next;
    }
    current.next = newNode;
}

Now I can actually use this like a real data structure:

const myMusic = new Playlist();
myMusic.append("Hotel California");
myMusic.append("Billie Jean");
myMusic.prepend("Bohemian Rhapsody");

// Resulting chain: Bohemian Rhapsody -> Hotel California -> Billie Jean

The trade-off here is clear. If I want to find the 100th song, I can't just say list[99] like I would with an array. I have to start at the head and hop 99 times. That's O(n) time complexity. But adding to the front? That's O(1)—instantaneous regardless of how many songs are in the playlist.




📋 Practical Task

Build a Browser History Stack

You are building a simplified browser history feature. Instead of a playlist, you need to implement a BrowserHistory class that uses a Linked List to keep track of visited URLs. Because the most recently visited page is the most important, you should store the history such that the most recent page is always at the head.

Requirements:

  • Create a PageNode class that stores a url and a next pointer.
  • Create a BrowserHistory class with a head property.
  • Implement a method visit(url) that adds a new URL to the front of the list (so the latest page is always the head).
  • Implement a method getCurrentPage() that returns the URL of the current head, or "No history" if the list is empty.
  • Implement a method goBack() that removes the current head and makes the next node the new head.

Test your code with this sequence:

const history = new BrowserHistory();
history.visit("google.com");
history.visit("github.com");
history.visit("stackoverflow.com");
console.log(history.getCurrentPage()); // Should be "stackoverflow.com"
history.goBack();
console.log(history.getCurrentPage()); // Should be "github.com"
Rating
0 0

There are no comments for now.

to be the first to leave a comment.