A linked list is one of the fundamental data structures every developer should be comfortable implementing from scratch — it shows up constantly in interviews, and understanding it makes structures like stacks, queues, and trees much easier to reason about. Unlike a JavaScript array, which stores elements in one contiguous block, a singly linked list stores each value in its own node, and every node holds a reference (pointer) to the next node in the chain.

The main benefit is O(1) insertion at the front of the list (no shifting of other elements, unlike Array.prototype.unshift), at the cost of O(n) access time since you have to walk the chain to reach a specific position.

Singly Linked List in JavaScript

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

class LinkedList {
  constructor() {
    this.head = null;
    this.size = 0;
  }

  // add a value to the end of the list
  append(value) {
    const newNode = new Node(value);
    if (!this.head) {
      this.head = newNode;
    } else {
      let current = this.head;
      while (current.next) current = current.next;
      current.next = newNode;
    }
    this.size++;
    return this;
  }

  // add a value to the front of the list — O(1)
  prepend(value) {
    const newNode = new Node(value);
    newNode.next = this.head;
    this.head = newNode;
    this.size++;
    return this;
  }

  // remove the first node matching this value
  delete(value) {
    if (!this.head) return this;

    if (this.head.value === value) {
      this.head = this.head.next;
      this.size--;
      return this;
    }

    let current = this.head;
    while (current.next && current.next.value !== value) {
      current = current.next;
    }
    if (current.next) {
      current.next = current.next.next;
      this.size--;
    }
    return this;
  }

  toArray() {
    const result = [];
    let current = this.head;
    while (current) {
      result.push(current.value);
      current = current.next;
    }
    return result;
  }
}

const list = new LinkedList();
list.append(10).append(20).append(30);
list.prepend(5);
console.log(list.toArray());

list.delete(20);
console.log(list.toArray());
console.log("Size:", list.size);

Output:

[ 5, 10, 20, 30 ]
[ 5, 10, 30 ]
Size: 3

Notice that append has to walk the whole list to find the last node, making it O(n) — if you need fast insertion at both ends, you'd extend this with a tail pointer, or use a doubly linked list where each node also points backward. The delete method similarly has to scan from the head until it finds a matching value, since there's no way to jump directly to a position the way you could with array indexing. In practice, JavaScript's built-in arrays are usually the better default choice — reach for a hand-rolled linked list mainly when you need guaranteed O(1) front insertion/removal, like implementing a queue, or when working through data-structure fundamentals.