user3612719
user3612719

Reputation: 129

Javascript forEach returning "undefined" as object variables

I'm trying implement a simple call to forEach to run the logMe function on all items in the automobiles array. The output is unexpected. All variables read "undefined."

    function Automobile(year, make, model, type) {
      this.year = year;
      this.make = make;
      this.model = model;
      this.type = type;
    }

    Automobile.prototype.logMe = function(boolVal) {
      if (boolVal == true) {
        console.log(this.year + ' ' + this.make + ' ' + this.model + ' ' + this.type);
      } else {
        console.log(this.year + ' ' + this.make + ' ' + this.model);
      }
    }

    var automobiles = [
      new Automobile(2010, "Toyota", "Tacoma", "Pickup"),
      new Automobile(2005, "Lotus", "Elise", "Roadster"),
      new Automobile(2008, "Subaru", "Outback", "Wagon")
    ];

    automobiles.forEach(Automobile.prototype.logMe.bind(true)); //the problem
    automobiles[0].logMe(true); //test logMe function

The output:

undefined undefined undefined

undefined undefined undefined

undefined undefined undefined

1995 Honda Accord Sedan

Upvotes: 1

Views: 992

Answers (2)

kukkuz
kukkuz

Reputation: 42352

Function.prototype.bind creates a new function and you must pass in the value of this - the construct which calls the function.

If you want to create an array of functions that can be called later like this, you should be using bind like below, otherwise just call the function inside the forEach.

var caller = [];
automobiles.forEach(function(element) {
  caller.push(Automobile.prototype.logMe.bind(element));
}, caller);
caller[0](true);

Demo below:

function Automobile(year, make, model, type) {
  this.year = year;
  this.make = make;
  this.model = model;
  this.type = type;
}

Automobile.prototype.logMe = function(boolVal) {
  if (boolVal == true) {
    console.log(this.year + ' ' + this.make + ' ' + this.model + ' ' + this.type);
  } else {
    console.log(this.year + ' ' + this.make + ' ' + this.model);
  }
}

var automobiles = [
  new Automobile(2010, "Toyota", "Tacoma", "Pickup"),
  new Automobile(2005, "Lotus", "Elise", "Roadster"),
  new Automobile(2008, "Subaru", "Outback", "Wagon")
];

var caller = [];

automobiles.forEach(function(element) {
  caller.push(Automobile.prototype.logMe.bind(element));
}, caller);

caller[0](true); //test logMe function

Upvotes: 1

outis
outis

Reputation: 77400

The first argument to Function.bind() is the value for this within the function. In your sample, this is bound to true, which is why you get undefined for the property values.

forEach will pass the element as the first argument to the callback. Thus, instead of passing a bound method, you can define a lambda that calls logMe on its 1st argument.

automobiles.forEach(function(car, i, cars) {car.logMe(true);});

Upvotes: 2

Related Questions