Reputation:
Background: I'm reading the online book Eloquent JavaScript and one of the exercises in Chapter 6 mentions that a "Sequence" can behave similarly to a linked list. Here is the link to the exercise, and I've copied a bit of relevant text:
Another solution is to avoid changing state in the object. You can expose a method for getting the current element (without advancing any counter) and another for getting a new sequence that represents the remaining elements after the current one (or a special value if the end of the sequence is reached).
I am trying to build a Sequence by recursively calling the implementing class's (ArraySeq) constructor within the interface class. However when running a test in node, I'm getting TypeError: Cannot read property '0' of undefined at Sequence.ArraySeq
.
I've copied and pasted my (incomplete) implementation:
/**
* Sequence interface
*/
function Sequence(current, rest) {
this.current = current;
this.rest = rest;
}
Object.defineProperty(Sequence.prototype, "end", {
get: function() {
return this.rest === undefined;
}
});
Sequence.prototype.next = function() {
return this.rest;
};
/**
* Array implementation of sequence
*/
function ArraySeq(array) {
if (array === []) {
Sequence.call(undefined, undefined);
} else {
Sequence.call(array[0], new ArraySeq(array.slice(1)));
}
}
ArraySeq.prototype = Object.create(Sequence.prototype);
/**
* Logs all elements in a Sequence
*/
function logSequence(sequence) {
while (sequence.rest !== undefined) {
console.log(sequence.current);
sequence = sequence.rest;
}
}
logSequence(new ArraySeq([1, 2]));
Thank you for reading this far, any help or guidance is greatly appreciated!
Upvotes: 0
Views: 101
Reputation: 198334
As I noted in comments:
array.splice[1]
will give you undefined. You want array.slice(1)
- the whole array without the first element: slice
, not splice
. array.splice(1)
will delete the second element from the array and return that element - not what you want.
You wrote Sequence
as a constructor, but you are not calling it as a constructor. Instead of Sequence.call
, use new Sequence
.
Conversely, you are calling new ArraySeq
, but ArraySeq
does not look like a constructor. Use just ArraySeq
, and make it return stuff (return new Sequence...
).
Use if (!array.length)
to test for array being non-empty. array === []
, and even array == []
, can never return true, because objects (and thus arrays) are compared based on object identity, not equality, and you just created a new one (so there is no chance it is the same object as something that already existed).
And of course, ArraySequence
is not defined; that was supposed to be ArraySeq
, right?
With those changes, your code works. EDIT: However, the exercise wants ArraySeq
to be an object, so still a bit more work... First of all, "interface" is not an object. It is just how an object should behave. My go at the exercise would be:
function ArraySeq(array) {
this.array = array;
this.index = 0;
}
Object.defineProperty(ArraySeq.prototype, "end", {
get: function() {
return this.index >= this.array.length;
}
});
Object.defineProperty(ArraySeq.prototype, "next", {
get: function() {
return this.array[this.index++];
}
});
/**
* Logs all elements in a Sequence
*/
function logSequence(sequence) {
while (!sequence.end) {
console.log(sequence.next);
}
}
logSequence(new ArraySeq([1, 2]));
The "interface" here is .end
and .next
. If you want to go the route of your quote, then it changes slightly. The interface here is .end
, .rest
and .value
:
function ArraySeq(array) {
this.array = array;
}
Object.defineProperty(ArraySeq.prototype, "end", {
get: function() {
return this.array.length == 0;
}
});
Object.defineProperty(ArraySeq.prototype, "rest", {
get: function() {
return new ArraySeq(this.array.slice(1));
}
});
Object.defineProperty(ArraySeq.prototype, "value", {
get: function() {
return this.array[0];
}
});
/**
* Logs all elements in a Sequence
*/
function logSequence(sequence) {
while (!sequence.end) {
console.log(sequence.value);
sequence = sequence.rest;
}
}
logSequence(new ArraySeq([1, 2]));
Upvotes: 1
Reputation: 106
first, splice
is method.
array.splice(1)
instead of array.splice[1]
.
and use array.length == 0 in array === [].
if two object is different object, then === operator treated as false even all element is same.
Upvotes: 0