Christoph Pohl
Christoph Pohl

Reputation: 325

JavaScript: Cannot set property of undefined

I'm pretty new to JS and I'm trying to wrap my head around the object topic in JS. What I'm trying to do is to set a property of an object prototype to an uninitialized array, so that I can later add multiple objects to that array (for instances of the prototype object) My code looks like this so far:

function cocktail(){
this.prototype.ingredients = [];
this.printIngredients = function() {
    var i;
    for (i = 0; i<this.ingredients.length; ++i) {
        console.log(this.ingredients.fluid);
        console.log(this.ingredients.amount);
        }
    }
}

var Mojito = new cocktail();
Mojito.ingredients.push({"fluid":"White Rum", "amount":0.05});
Mojito.printIngredients();

That throws:

TypeError: Cannot set property 'ingredients' of undefined

If I change my code into :

this.ingredients = [];

it works but the printIngredients() method prints undefined twice. When I do:

var array = [];
array.push({"a":1, "b":2});
console.log(array[0].a, array[0].b)

everything works as I would expect it to. Can someone clarify what I'm doing wrong and where my thoughts got mixed up?

Upvotes: 2

Views: 9137

Answers (3)

EMMANUEL OKELLO
EMMANUEL OKELLO

Reputation: 178

well, first you want to remove printIngredients method out of the constructor function, it will improve performance when it comes to a larger project since you don't have to create different copies every time you instantiate the constructor function, secondly, it is a convention to capitalize the first letter of your constructor. Last but not least, use let and const as they limit the scope to block rather than var that's function scope.

function Cocktail(){
this.ingredients = []; 
}

Cocktail.prototype.printIngredients = function() {
    // for in ... iterates on keys rather than values
    for (let i in this.ingredients) {
        console.log(this.ingredients[i].fluid);//use the counter variable to get the fluid value at current counter value 
        console.log(this.ingredients[i].amount);//use the counter variable to get the amount value at current counter value 
        }
    }

const Mojito = new Cocktail();
console.log(Mojito.ingredients)
Mojito.ingredients.push({"fluid":"White Rum", "amount":0.05});
Mojito.printIngredients();

Upvotes: 0

Hugo Wood
Hugo Wood

Reputation: 2260

Alternatively, if you are familiar with class-based languages, you could use modern JavaScript to avoid some of the confusion.

class Cocktail {
  constructor() { 
      this.ingredients = [] 
  }

  printIngredients() {
      // let is like var, but scoped to blocks instead of functions
      // for...of iterates on values instead of keys/indices
      for (let ingredient of this.ingredients) {
          console.log(ingredient.fluid)
      }
  }
}

This kind of JavaScript is available from:

  • Chrome 49
  • Edge 13
  • Firefox 44
  • Node.js 6

Documentation:

Upvotes: 0

gurvinder372
gurvinder372

Reputation: 68393

Change your code to

function cocktail(){
this.ingredients = []; //this doesn't have prototype property
this.printIngredients = function() {
    var i;
    for (i = 0; i<this.ingredients.length; ++i) {
        console.log(this.ingredients[i].fluid);//use the counter variable to get the fluid value at current counter value 
        console.log(this.ingredients[i].amount);//use the counter variable to get the amount value at current counter value 
        }
    }
}

var Mojito = new cocktail();
console.log(Mojito.ingredients)
Mojito.ingredients.push({"fluid":"White Rum", "amount":0.05});
Mojito.printIngredients();

Upvotes: 3

Related Questions