Trying to make a Node class function that takes an array of items and pushes them all to a linked list

Viewed 86

This is the code I have written so far. I don't think I am necessarily on the right track using a loop in the 'Node' function...

function LinkedList() {
  this.head = null;
  this.tail = null;
  this.length = 0;
}

function Node(...val) {
  if (Array.isArray(val)) {
    for (let i = 0; i < val.length; i++) {
      this.push(val[i])
    }
  }
  this.value = val;
  this.next = null;
}

LinkedList.prototype.push = function(val) {
    let newNode = new Node(val);
    if(!this.head) {
        this.head = newNode;
        return this.head;
    }
    let tail = this.head;
    while (tail.next !== null) {
        tail = tail.next;
    }
    tail.next = newNode;

    return this.head;
};

Here are the tests I am trying to run on it...

const newList = new LinkedList(5, 1, 2, 6, 8);
console.log(newList.head.value);
console.log(newList.head.next.value);
console.log(newList.head.next.next.value);
console.log(newList.head.next.next.next.value);
console.log(newList.head.next.next.next.next.value);
console.log(newList.head.next.next.next.next.next);

The output of the console logs is just "Cannot read properties of null (reading 'value').

Can someone point out what I am doing wrong or where to head next? Thank you for your time!

1 Answers

The problem is that your LinkedList constructor does not have any parameters, so when you construct it with new LinkedList(5, 1, 2, 6, 8); those arguments are ignored.

You probably misplaced the argument processing, and put it in the Node constructor, while it should have been in the LinkedList constructor.

So move that code, and parameter definition, and it will work.

Some other things to improve:

  • It is not necessary to do the Array.isArray check, since the ...val parameter declaration will always give you an array when the function is called -- it could have length 0 when no arguments are passed, but it will still be an array.

  • The push method should not have to go through a loop. You already have a tail reference, so use it.

  • The push method should update the length property -- since you have it.

  • The push method should not have to return anything. The modification is done in the LinkedList instance, and the caller should not really have to know about the Node instance that was created.

Here is the working version:

function LinkedList(...val) {
  this.head = null;
  this.tail = null;
  this.length = 0;
  for (let i = 0; i < val.length; i++) {
    this.push(val[i]);
  }
}

function Node(val) {
  this.value = val;
  this.next = null;
}

LinkedList.prototype.push = function(val) {
    let newNode = new Node(val);
    if (!this.head) {
        this.head = newNode;
    } else {
        this.tail.next = newNode;
    }
    this.tail = newNode;
    this.length++;
};

const newList = new LinkedList(5, 1, 2, 6, 8);
console.log(newList.head.value);
console.log(newList.head.next.value);
console.log(newList.head.next.next.value);
console.log(newList.head.next.next.next.value);
console.log(newList.head.next.next.next.next.value);
console.log(newList.head.next.next.next.next.next);

Modernising

Since your code uses spread syntax, there is no reason why you shouldn't also use the class syntax, and the for..of loop.

And to avoid that the caller has to be aware of the Node instances, make your LinkedList class iterable using Symbol.iterator:

class LinkedList {
    constructor(...values) {
        this.head = null;
        this.tail = null;
        this.length = 0;
        for (let value of values) {
            this.push(value);
        }
    }
    push(val) {
        let newNode = new Node(val);
        if (!this.head) {
            this.head = newNode;
        } else {
            this.tail.next = newNode;
        }
        this.tail = newNode;
        this.length++;
    }
    *[Symbol.iterator]() {
        let node = this.head;
        while (node) {
            yield node.value;
            node = node.next;
        }
    }
}

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

const newList = new LinkedList(5, 1, 2, 6, 8);
for (let value of newList) {
    console.log(value);
}

Related