1

I'm having trouble trying to figure out why I am not able to use 'this.count' in a prototype of my Game constructor without getting NaN or undefined. I am using it to track points every time the user answers one of four questions correctly.

I had assumed that once a property was declared inside a constructor, it is available for use in any of its prototypes? Thank you in advance.

var questions = [
  {question: "What programming language does the library 'jQuery' belongs to?",
  answer: "JAVASCRIPT"},
  {question: "What programming language does 'Sass' builds upon?",
  answer: "CSS"},
  {question: "How do you abbreviate Hyper Text Markup Language?",
  answer: "HTML"},
  {question: "What company does the framework 'Bootstrap' belong to?",
  answer: "TWITTER"}
];

var Game = function(array) {
  this.array = array;
  this.count = 0;   // this.count is set to 0 //
}

var guess = new Game(questions);

Game.prototype.play = function() {
  console.dir(this.array);
  console.dir(this.count);
  $('button').click(function() {
    for (var i = 0; i < this.array.length; i++) {
        var newGuess = prompt(this.array[i].question).toUpperCase();
        if (newGuess === this.array[i].answer) {
            ++this.count;    // Problem happens here //
            console.log(this.count);
        } else {
            alert('Incorrect.');
        }
    }
    alert('You answered ' + this.count + ' out of 4 correct.');
  });
}
guess.play();
Jose
  • 4,880
  • 8
  • 27
  • 49
  • Right, because `this` isn't your `Game` instance and therefore doesn't have a `count` property. `++undefinedproperty` gives `NaN` – Kevin B Aug 06 '15 at 20:42

2 Answers2

1

Inside of the anonymous function the 'this' is referencing the anonymous function itself, not Game. Add:

    var self = this;

before the .click(...) and replace the 'this' with 'self'.

nurdyguy
  • 2,876
  • 3
  • 25
  • 32
0

It's because the this you are referring to is the this of the click handler function, which does not contain count:

Solution 1 - this alias:

Game.prototype.play = function() {
var that = this; // the alias

  console.dir(this.array);
  console.dir(this.count);
  $('button').click(function() {
    for (var i = 0; i < this.array.length; i++) {
        var newGuess = prompt(this.array[i].question).toUpperCase();
        if (newGuess === this.array[i].answer) {
            ++this.count;    // Problem happens here //
            console.log(this.count);
        } else {
            alert('Incorrect.');
        }
    }
    alert('You answered ' + that.count + ' out of 4 correct.'); // using the alias
  });
}

Solution 2 - using bind to change this:

  $('button').click(function() {
    for (var i = 0; i < this.array.length; i++) {
        var newGuess = prompt(this.array[i].question).toUpperCase();
        if (newGuess === this.array[i].answer) {
            ++this.count;    // Problem happens here //
            console.log(this.count);
        } else {
            alert('Incorrect.');
        }
    }
    alert('You answered ' + this.count + ' out of 4 correct.');
  }.bind(this)); // the this of the outer closure is now the this of the click handler function
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • The code blocks you provided were extremely helpful. Used the bind method. Thank you! – Jose Aug 06 '15 at 20:49