user6840964
user6840964

Reputation:

Having trouble implementing my stack class in Javascript

I'm creating my stack class. I followed a javascript data structures book but I changed some functions and I keep getting an error that says "s.length is not a function." I have a length function but I wonder since there is a keyword 'length' in javascript then having the same name as a function might be causing an issue.:

// LIFO

function Stack() 
{
    this.dataStore = [];
    // top of the stack
    this.top = 0;
    this.push = push;
    this.pop = pop;
    this.peek = peek;
 }

function push(element)
{
    // when new element is pushed, it needs to be stored
    // in the top position and top var needs to be incremented
    // so the new top is the next empty pos in the array 
    //this.dataStore(this.top++) = element;
    // the increment op after the call ensures that the 
    // current value of top is used to place the new element
    // at the top of the stack before top is incremented 
    this.dataStore.push(element);
 }

function pop()
{
    // returns element in top pos of stack and then decrements
    // the top variable
    //return this.dataStore[--this.top];
    return this.dataStore.pop(element);
}

function peek()
{
    // returns the top element of the stack by accessing 
    // the element at the top-1 position of the array
    //return this.dataStore[this.top-1];
    return this.dataStore[items.length-1];
}

function length()
{
    //return this.top;
    return this.dataStore.length;
}

function clear()
{
    //return this.top = 0;
    return this.dataStore = [];
}

var s = new Stack();
s.push("David");
s.push("Raymond");
s.push("Bryan"); 
console.log("length: " + s.length());

Upvotes: 0

Views: 91

Answers (3)

Redu
Redu

Reputation: 26161

Whatever data structures book you are following, it's doing it wrong; at least in JS.

In JS you are expected to enlist the utility methods in the prototype of the instantiated objects so that they don't occupy redundant memory space for each Stack object instantiated.

So far i am in line with @Xeren Narcy's answer, however this stack thing is a perfect candidate to use array sub-classing so that you don't need to re-implement the standard array methods like .pop() and .push() under the Stack() constructor's prototype. Instead you can make Array.prototype the super class of Stack.prototype (sub classing here). On top of that, since our Stack objects will inherit from a proper Array object their magical length property will work just like any array. (even if you assign items through the index.)

Lets see the implementation...

function Stack(...a){
  var stack = new Array(...a);
  Object.setPrototypeOf(stack, Stack.prototype);
  return stack;
}
Stack.prototype = Object.create(Array.prototype); // now stack has full access to array methods.
Stack.prototype.constructor = Stack;              // now Stack is a proper constructor
Stack.prototype.peak = function(){return this[this.length-1]}; // add Stack "only" methods to the Stack.prototype.

var s = new Stack(1,2,3,4,1);
console.log(s.peak());
s[s.length] = 7;
console.log(s.length);
s.push(42);
console.log(s);
console.log(s.length);

I hope it helps.

Upvotes: 0

Xeren Narcy
Xeren Narcy

Reputation: 875

To begin with, I don't believe it's a good idea to use this pattern:

function MyClass () {
  this.method = method;
}
function method () {
  // ...
}

It pollutes the namespace, and length being a common property it will quickly become confusing. I prefer to use explicit overriding of the prototype object after defining the constructor function, which avoids the need for global-functions-as-methods.

Perhaps something like this would be better? (comments omitted for brevity)

function Stack() 
{
    this.dataStore = [];
    // top of the stack
    this.top = 0;
    // this.push = push;
    // this.pop = pop;
    // this.peek = peek;
    // this.length = length;
 }

Stack.prototype.push = function(element)
{
    this.dataStore.push(element);
 }

Stack.prototype.pop = function()
{
    return this.dataStore.pop( /*element*/ );
}

Stack.prototype.peek = function()
{
    return this.dataStore[ /*items*/ this.dataStore.length-1];
}

Stack.prototype.length = function()
{
    return this.dataStore.length;
}

Stack.prototype.clear = function()
{
    return this.dataStore = [];
}

Then your example will work.

Regarding length as a user-defined property

Testing this quickly, javascript has no problem with length being overridden in this way. It's because length is not a property of objects (arrays yes, however), so you're free to use it as a property or method name in your own classes.

Upvotes: 2

Tim Grant
Tim Grant

Reputation: 3458

"is not a function" errors like this one typically mean you tried to call a non-function object attribute as a function. This is typically done by putting parentheses after the attribute.

You did this here: console.log("length: " + s.length());.

Remove the parentheses:

console.log("length: " + s.length);.

But your stack object doesn’t have a length attribute, so you’ll be trading one error for another. I am not exactly sure what you are trying to achieve checking the objects length, but check this question on how to get an object’s length in JavaScript.

This goes beyond the question asked, but you are having trouble because you are trying to push onto your object, while you probably want to be pushing onto the dataStore array inside your object, like this:

s.dataStore.push("David");

Upvotes: 0

Related Questions