I'm building a linked list by my own. I tried to assign a generator as value of a key/value WeakMap in the constructor. The _iterator
is a WeakMap because is a private member that I want use to make simple iterate over my data structure, but I don't want make the generator visible outside because otherwise I'll break abstraction. But I have the error SyntaxError: missing ( before formal parameters
. What is the problem?
class Node{
constructor(value){
this.value = value;
this.next = null;
}
}
//IIFE function that return the class.
const SingleLinkedList = (() => { //Here use IIFE to create a new block scope for private variables
let _counts = new WeakMap();
let _head = new WeakMap();
let _tail = new WeakMap();
let _iterator = new WeakMap();
class SingleLinkedList {
constructor() {
_counts.set(this, 0);
_head.set(this, null);
_tail.set(this, null);
let instance = this;//closure
_iterator.set(this,(function* [Symbol.iterator](){
let n=_head.get(instance);
while(n){
yield n;
n = n.next;
}
}));
}
get counts() { //read only get accessor property
return _counts.get(this);
}
isEmpty() {
return !this.counts; //or return !_head.get(this)
}
//insert a new Node (in tail) with the desired value
push(value) {
let n = new Node(value);
if (this.isEmpty())
_head.set(this, n);
else {
let tail = _tail.get(this); //tail is a pointer to the node-tail
tail.next = n; //old tail-node will point to new node
}
//the following instructions are common to both the cases.
_tail.set(this, n); //set new tail
_counts.set(this, this.counts+1); //increment item counter
return this; //to allow multiple push call
}
//Generator to return the values
*[Symbol.iterator](){
let n = _head.get(this);
while(n){
yield n.value;
n=n.next;
}
}
//the the values of each node
print() {
let output = "";
for(let el of this)
output += `${el} `;
console.log(output);
}
}
return SingleLinkedList;
})();
let myLinkedList = new SingleLinkedList();
myLinkedList.push(3);
myLinkedList.push(5);
myLinkedList.print();
/*for(let x of myLinkedList)
console.log(x);*/
Function expressions can't have computed names, that syntax is only allowed on object literal members or class members, so define the constructor of your SingleLinkedList
like this instead:
constructor() {
_counts.set(this, 0);
_head.set(this, null);
_tail.set(this, null);
let instance = this;//closure
_iterator.set(this, function* (){
// remove the computed name ---^
let n=_head.get(instance);
while(n){
yield n;
n = n.next;
}
});
}
Perhaps even more useful is knowing how to debug syntax errors in the future so you don't need to ask questions like this again. If you open your developer console by pressing F12, you'll see a log that looks something like this:
Click that link and it will take you straight to the location of the error:
Just for fun, here's my suggested rewrite using some more modern features of ECMAScript like private fields:
class Node {
next = null;
constructor (value) {
this.value = value;
}
}
class SingleLinkedList {
#size = 0;
#head = null;
#tail = null;
// read only get accessor property
get size () {
return this.#size;
}
isEmpty () {
return this.#size === 0;
}
// insert a new Node (in tail) with the desired value
push (value) {
const node = new Node(value);
if (this.isEmpty()) {
this.#head = node;
} else {
this.#tail.next = node;
}
// the following instructions are common to both the cases.
this.#tail = node;
this.#size++;
// to allow multiple push call
return this;
}
// generator to return the values
*[Symbol.iterator] () {
for (let current = this.#head; current; current = current.next) {
yield current.value;
}
}
// the the values of each node
toString () {
return [...this].join(' ');
}
}
const myLinkedList = new SingleLinkedList();
myLinkedList.push(3).push(5);
console.log(myLinkedList.toString());