Meal Maker:Why am I getting a RangeError?

https://www.codecademy.com/courses/introduction-to-javascript/projects/meal-maker

const menu = {
  _courses: {
    appetizers: [],
    mains: [],
    desserts: []
  },
  get appetizers(){
    return this._courses.appetizers;
  },
  get mains(){
    return this._courses.mains;
  },
  get desserts(){
    return this._courses.desserts;
  },
  set appetizers(appetizers){
    return this._courses.appetizers = appetizers;
  },
  set mains(mains){
    return this._courses.mains = mains;
  },
  set desserts(desserts){
    return this._courses.desserts = desserts;
  },
  get _courses(){
    return {
      appetizers: this.appetizers,
      mains: this.appetizers,
      desserts: this.desserts
    }
  },
  addDishToCourse(courseName, name, price){
    const dish = {
      name,
      price
    };
    return this._courses[courseName].push(dish);
  },
  getRandomDishFromCourse(courseName){
    const dishes = this._courses[courseName];
    const randomIndex = Math.floor(Math.random() * dishes.length)
    return dishes[randomIndex]
  },
  generateRandomMeal(){
    const appetizer = this.getRandomDishFromCourse('appetizers')
    const main = this.getRandomDishFromCourse('mains')
    const dessert = this.getRandomDishFromCourse('desserts')
    const totalPrice = appetizer.price + main.price + dessert.price;
    return `Your meal is ${appetizer.name}, ${main.name}, ${dessert.name}. The price is ${totalPrice}.`;
  }
};
menu.addDishToCourse('appetizers', 'Chips and Salsa', 1.00)
menu.addDishToCourse('appetizers', 'Garlic Bread', 3.00)
menu.addDishToCourse('appetizers', 'Salad', 2.50)

menu.addDishToCourse('mains', 'Rice and Steak', 14.99)
menu.addDishToCourse('mains', 'Tacos', 13.99)
menu.addDishToCourse('mains', 'Chili', 20.99)

menu.addDishToCourse('desserts', 'Chocolate Sundae', 7.99)
menu.addDishToCourse('desserts', 'Caramel Dipped Bananas', 8.99)
menu.addDishToCourse('desserts', 'Vanilla Sundae with Chocolate Chips', 10.99)
const meal = menu.generateRandomMeal();
console.log(meal);

This then prints:

/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:26
    return {
    ^

RangeError: Maximum call stack size exceeded
    at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:26:5)
    at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:8:16)
    at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:27:23)
    at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:8:16)
    at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:27:23)
    at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:8:16)
    at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:27:23)
    at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:8:16)
    at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:27:23)
    at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:8:16)

The getter will endlessly call itself. Although, in your case it looks a little more complex. Seems two getters call each other constantly.

the moment you try to use the appetizer getter:

  get appetizers(){
    return this._courses.appetizers;
  },

this._courses will invoke the getter:

get _courses(){
    return {
      appetizers: this.appetizers,
      mains: this.appetizers,
      desserts: this.desserts
    }
  },

which will invoke the appetizers getter (because of this.appetizers. And so forth

to avoid this problem, the property is prefixed with an underscore, and then the getter is without prefix/underscore. So that the property and getter don’t have the same name.

So, I need to remove the underscore from in front of my getter name. Honestly I don’t even understand getters or setters, and I also saw that this code would work without them?

well, the underscore is only a convention, we could do:

myObj = {
 a: 3,
 get b()
 {
    return this.a;
 }
}

console.log(myObj.b);

but that is just confusing. a = b? what?

well, because you defined getters, we can now do:

menu.apptizers

despite that the actual property is nested in the courses object.

or we can even change the default behavior:

myObj = {
   _a: [],
   get a()
   {
      return this._a.join('-')
   },
   set a(valIn)
   {
      this._a.push(valIn);
   }
}

myObj.a = 3;
myObj.a = 4;
myObj.a = 5;
console.log(myObj.a);

or could use the setter for validation. (allowing numeric values only for example)

I thought setters were the ones that were supposed to change things. So then why is your getter joining a by the dashes? If a getter can mutate things then why do you even need a setter?

the getter isn’t mutating data, merely presenting the data differently. .join() results in a copy. The list isn’t mutated in any way:

console.log(myObj._a);

Well, it didn’t mutate because you were using .join(). What if you used a destructive method with a getter?

such as?

But destructive doesn’t sounds good for a getter.

My example was merely to show some of the possibilities with getters.

Hm, yeah sorry. I was just wondering why we need setters if a getter can do the same as a setter.

but the getter and setter don’t do the same thing. The getter is used for reading:

myObj.a

while the setter is used for assignment:

myObj.a = 'new value'

see the valIn parameter of my setter? I get the i used for assignment, so now I can use that in the setter. This is with getter not possible

Programming languages give you a certain degree of freedom, some more then others. But then its still our responsibility to use the tools sensible. Trust me, once you have taken over a crappy programming project, you never wish that to anyone else :wink:

1 Like

Ok thanks. So basically, you can’t use getters to reassign or mutate a value. But you can use them to read the value stored in that property. One more question, why did we make all those getters and setters in our code? I don’t see them being used at all. The only one I see being used are the methods. And the code works fine without them.

I suppose we could:

myObj = {
  _a: 3,
  get a()
  {
     this._a = 5;
   }
}

myObj.a
console.log(myObj._a);

please don’t do this. Its so weird, wrong and illogical.

we could use the setter to use .push() (I believe this also an additional challenge):

set appetizers(appetizer){
    return this._courses.appetizers.push(appetizer)
  },

Given we have the setters, we could use these directly in add dish to course:

return this[courseName] = dish;

the courseName should call the setter.

1 Like

I’m still not getting everything competely, but I’m sure I’ll figure it out later. For now, I understand why my code was throwing a RangeError. Thanks for helping. :slight_smile:

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.