-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
168: Implementing a Linked List in JavaScript
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
PageNodeclass that stores aurland anextpointer. - Create a
BrowserHistoryclass with aheadproperty. - 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"There are no comments for now.