SOURCE

class LinkedList {
    length = 0

    head = null

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

    append(data) {
        const newNode = new this.Node(data)

        if (this.length === 0) {
            this.head = newNode
        } else {
            let currentNode = this.head

            while (currentNode.next !== null) {
                currentNode = currentNode.next
            }

            currentNode.next = newNode
        }

        this.length++
    }

    toString() {
        let currentNode = this.head
        let result = ''

        while (currentNode) {
            result += currentNode.data + ''
            currentNode = currentNode.next
        }

        return result
    }

    insert(position, data) {

        if (position < 0 || position > this.length) return false

        const newNode = new this.Node(data)

        if (position === 0) {
            newNode.next = this.head

            this.head = newNode
        } else {
            let currentNode = this.head
            let previousNode = null
            let index = 0
            while (index++ < position) {
                previousNode = currentNode
                currentNode = currentNode.next
            }

            newNode.next = currentNode
            previousNode.next = newNode
        }

        this.length++
        return newNode
    }

    getData(position) {
        if (position < 0 || position >= this.length) return false

        let currentNode = this.head
        let index = 0
        while (index++ < position) {
            currentNode = currentNode.next
        }

        return currentNode.data
    }

    indexOf(data) {
        let currentNode = this.head
        let index = 0
        while (currentNode) {
            if (currentNode.data === data) {
                return index
            }
            currentNode = currentNode.next
            index++
        }

        return -1
    }

    update(position, data) {
        if (position < 0 || position >= this.length) return false

        let currentNode = this.head
        let index = 0

        while (index++ < position) {
            currentNode = currentNode.next
        }

        currentNode.data = data

        return currentNode
    }

    removeAt(position) {
        if (position < 0 || position >= this.length) return false

        let currentNode = this.head
        if (position === 0) {
            this.head = this.head.next
        } else {
            let previousNode = null
            let index = 0

            while (index++ < position) {
                previousNode = currentNode
                currentNode = currentNode.next
            }

            previousNode.next = currentNode.next
        }

        this.length--

        return currentNode
    }

    remove(data) {
        this.removeAt(this.indexOf(data))
    }

    isEmpty() {
        return this.length === 0
    }

    size() {
        return this.length
    }
}

class DoublyLinkedList extends LinkedList {
    DoublyNode = class {
        data
        next = null
        prev = null
        constructor(data) {
            this.data = data
        }
    }
    constructor(data) {
        super(data)
        this.tail = null
    }

    append(data) {
        const newNode = new this.DoublyNode(data)

        if (this.head === null) {
            this.head = newNode
            this.tail = newNode
        } else {
            this.tail.next = newNode
            newNode.prev = this.tail
            this.tail = newNode
        }

        this.length++
    }

    insert(position, data) {
        if (position < 0 || position > this.length) return false

        const newNode = new this.DoublyNode(data)

        if (position === 0) {
            if (this.head === null) {
                this.head = newNode
                this.tail = newNode
            } else {
                newNode.next = this.head
                this.head.prev = newNode
                this.head = newNode
            }
        } else if (position === this.length) {
            this.tail.next = newNode
            newNode.prev = this.tail
            this.tail = newNode
        } else {
            let targetIndex = 0
            let currentNode = this.head
            let previousNode = null

            while (targetIndex++ < position) {
                previousNode = currentNode
                currentNode = currentNode.next
            }

            previousNode.next = newNode
            newNode.prev = previousNode

            newNode.next = currentNode
            currentNode.prev = newNode
        }

        this.length++

        return true
    }
    // getData() 继承单向链表
    getData(position) {
        return super.getData(position);
    }

    // indexOf() 继承单向链表
    indexOf(data) {
        return super.indexOf(data);
    }
    removeAt(position) {
        if (position < 0 || position > this.length - 1) return null

        let currentNode = this.head
        if (position === 0) {

            if (this.length === 1) {
                this.head = null
                this.tail = null
            } else {
                this.head = this.head.next
                this.head.prev = null
            }
        } else if (position === this.length - 1) {

            currentNode = this.tail
            this.tail.prev.next = null
            this.tail = this.tail.prev
        } else {
            let targetIndex = 0
            let previousNode = null
            while (targetIndex++ < position) {
                previousNode = currentNode
                currentNode = currentNode.next
            }

            previousNode.next = currentNode.next
            currentNode.next.prev = previousNode
        }

        this.length--
        return currentNode.data
    }

    update(position, data) {
        const result = this.removeAt(position)

        this.insert(position, data)

        return result
    }

    forwardToString() {
        let currentNode = this.head;
        let result = '';

        // 遍历所有的节点,拼接为字符串,直到节点为 null
        while (currentNode) {
            result += currentNode.data + '--';
            currentNode = currentNode.next;
        }

        return result;
    }

    backwardString() {
        let currentNode = this.tail;
        let result = '';

        // 遍历所有的节点,拼接为字符串,直到节点为 null
        while (currentNode) {
            result += currentNode.data + '--';
            currentNode = currentNode.prev;
        }

        return result;
    }
}

const doublyLinkedList = new DoublyLinkedList();

// append() 测试
doublyLinkedList.append('ZZ');
doublyLinkedList.append('XX');
doublyLinkedList.append('CC');
console.log(doublyLinkedList);

// insert() 测试
doublyLinkedList.insert(0, '00');
doublyLinkedList.insert(2, '22');
console.log(doublyLinkedList);

// getData() 测试
console.log(doublyLinkedList.getData(1)); //--> ZZ

// indexOf() 测试
console.log(doublyLinkedList.indexOf('XX')); //--> 3
console.log(doublyLinkedList);

// removeAt() 测试
doublyLinkedList.removeAt(0);
doublyLinkedList.removeAt(1);
console.log(doublyLinkedList);

// update() 测试
doublyLinkedList.update(0, '111111');
console.log(doublyLinkedList);

// remove() 测试
console.log(doublyLinkedList.remove('111111'));
console.log(doublyLinkedList.remove('22222'));
console.log(doublyLinkedList);

// forwardToString() 测试
console.log(doublyLinkedList.forwardToString());

// backwardString() 测试
console.log(doublyLinkedList.backwardString());
console 命令行工具 X clear

                    
>
console