1
\$\begingroup\$

I'm looking for feedback on my singly linked list implementation in JavaScript. Please let me know if you have any suggestions on coding style, documentation, bug fixes, etc.

UML / code overview

LinkedList _head - The first element in the list _size - The number of elements in the list getSize() Returns the number of elements in the list get(index) Returns the node at index Throws a ReferenceError if index is not specified Throws a RangeError if index is out of range getFirst() Returns the first element in the list Calls and returns this.get(0) getLast() Returns the last element in the list Calls and returns this.get(this._size - 1) add(node, index) Inserts the given node at the specified index Throws a ReferenceError if node is not passed Throws a TypeError if node is not an instance of ListNode addFirst(node) Inserts the given node at the front of the list Calls and returns add(node, 0) addLast(node) Appends the given node at the end of the list Calls and returns add(node, this._size - 1) remove(index) Removes and returns the node at the specified index Throws a ReferenceError if index is undefined Throws a RangeError if index is not between 0 and this._size removeFirst() Removes and returns the first node in the list Calls and returns remove(0) removeLast() Removes and returns the last node in the list Calls and returns remove(0) clear() Removes all elements in the list set(index, node) Replaces the node at index with the given node Calls this.remove(index) then calls and returns this.add(node, index) indexOf(value) Returns -1 or the first index value is found at Throws a ReferenceError if value is undefined lastIndexOf(value) Returns -1 or the last index value is found at Throws a ReferenceError if value is undefined contains(value) Returns true/false if the value is/not in the list ListNode _value - The value this node holds _next - The next node in the list getValue() setValue(value) getNext() setNext(node) 

Code

I've left out the ListNode class because there's nothing more to it than the UML above.

class LinkedList { // Initializes the list by setting the head to null, // and the size to 0 constructor() { this._head = null; this._size = 0; } // Returns the number of nodes in the list getSize() { return this._size; } // Returns the head of the list getFirst() { return this._head; } // Returns the tail of the list getLast() { return this.get(this._size - 1); } // Returns the node at the specified index get(index) { // If the index parameter was not specified if (index === undefined) { throw new ReferenceError('no index was specified', 'LinkedList.js'); } // Make sure the index is in range if (index < 0 || index >= this._size) { const msg = `Index (${index}) out of range; List size (${this._size})`; throw new RangeError(msg, 'LinkedList.js'); } let current = this._head; for (let i = 0; i < index; i++) { current = current.getNext(); } return current; } // Inserts the given node at the specified index add(node, index) { // If the node parameter was not specified if (node === undefined) { throw new ReferenceError('no node was specified', 'LinkedList.js'); } // Make sure node is a ListNode if (!(node instanceof ListNode)) { const msg = "add(node, index): node must be of type ListNode"; throw new TypeError(msg, 'LinkedList.js'); } // The index parameter is optional. If not defined, add node to the end if (index === undefined) { index = this._size; } // Make sure the index is in range if (index < 0 || index > this._size) { const msg = `Index (${index}) out of range; List size (${this._size})`; throw new RangeError(msg, 'LinkedList.js'); } // If inserting the node at the beginning of the list if (index === 0) { // Set the node's next to point to the current head node.setNext(this._head); // Replace the current head with the new node this._head = node; this._size++; return node; } else { // The node just before the insertion index let previous = this.get(index - 1); // The node at the insertion index let next = previous.getNext(); // Set the node at the insertion index previous.setNext(node); node.setNext(next); this._size++; return node; } } // Inserts the given node at the beginning of the list addFirst(node) { return this.add(node, 0); } // Appends the given node at the beginning of the list addLast(node) { return this.add(node, this._size); } // Removes and returns the node at the specified index remove(index) { // If the index parameter was not specified if (index === undefined) { throw new ReferenceError('no index was specified', 'LinkedList.js'); } // Make sure the index is in range if (index < 0 || index > this._size) { const msg = `Index (${index}) out of range; List size (${this._size})`; throw new RangeError(msg, 'LinkedList.js'); } // If removing the head of the list if (index === 0) { const removed = this._head; this._head = this._head.getNext(); this._size--; return removed; } else { // The node at the index before the one to be removed let previous = this.get(index - 1); // The node to be removed let removed = previous.getNext(); // Removes the node at index by setting the next pointer of the node at // index-1 to the node at index+1, skipping the node at index previous.setNext(removed.getNext()); this._size--; return removed; } } // Removes and returns the head of the list removeFirst() { return this.remove(0); } // Removes and returns the last node in the list removeLast() { return this.remove(this._size - 1); } // Empties the list by setting the head to null and sets the size to 0 clear() { this._head = null; this._size = 0; } // Replaces the node at the specified index with the given node set(index, node) { // Remove the node currently at index this.remove(index); // Inserts the new node at the specified index return this.add(node, index); } // Returns the index that the value is found at, -1 if the value is not found indexOf(value) { // If the index parameter was not specified if (value === undefined) { throw new ReferenceError('no value was specified', 'LinkedList.js'); } // If the list is empty, return -1 indicating the value wasn't found if (this._head == null) { return -1; } let current = this._head; let index = 0; while (current.getNext() != null) { if (current.getValue() === value) { return index; } current = current.getNext(); index++; } return -1; } // Returns the last index the value is found at, -1 if it is not found lastIndexOf(value) { // If the index parameter was not specified if (value === undefined) { throw new ReferenceError('no value was specified', 'LinkedList.js'); } // If the list is empty, return -1 indicating the value wasn't found if (this._head == null) { return -1; } let current = this._head; let lastMatch = -1; let index = 0; while (current != null) { // If a match is found, update the lastMatch to the current index if (current.getValue() === value) { lastMatch = index; } current = current.getNext(); index++; } return lastMatch; } // Returns true if the value is in the list, false otherwise contains(value) { // Returns true if indexOf() finds the value, false if it does not return (this.indexOf(value) !== -1); } } 
\$\endgroup\$

    1 Answer 1

    1
    \$\begingroup\$

    You could change your if condition

    if (index === undefined) { throw RangeError('no index passed') } else { // do the funk }

    by

    if (typeof(index) !== "undefined" && index !== null) { throw RangeError('no index passed') } else { // do the funk }

    Because in your case you will have an error if you pass some null in your functions.

    \$\endgroup\$
    2
    • \$\begingroup\$Would it be better to just do if (index == null) since that will be true if index is undefined and if index is null?\$\endgroup\$
      – Matt C
      CommentedOct 12, 2016 at 18:17
    • 1
      \$\begingroup\$@MatthewCliatt try not to use == it is bad practice. It could be hard to debug when your codebase is going to grow ;)\$\endgroup\$CommentedOct 13, 2016 at 17:08

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.