phantom phantom - 2 months ago 6
Javascript Question

using this on an objects method is returning an error

I feel my whole understanding of

this
has been thrown up in the air.

I have a
Quiz
object which holds the necessary variables and methods required to play the quiz.

I am trying to reference a method of Quiz from another method in Quiz (
getQuestion
in
skipQuestion()
) however, I am seeing a message in the console saying that
this.getQuestion
is not defined. I was under the impression that
this
in this case refers to the object it is in, hence the function in question should be referred to as
this.getQuestion()
.

The error message I am getting is
script.js:18 Uncaught TypeError: this.getQuestion is not a function


Can anyone explain what is going wrong here?

In my
init
function it seems that
this
refers to the
Quiz
object, but in
skip question
it seems to change. Is this down to query having a different definition of
this
? where do you draw the line, and when is the context of
this
changed?

(function(window){

$(document).ready(function(){
var Quiz = {

score : 0,
question: '',
answer: '',

init: function() {
this.getQuestion();
this.checkAnswer();
this.skipQuestion();
},

skipQuestion: function() {
$('#skip').click(function(){
this.getQuestion();

})
},

getQuestion: function() {
$.get('http://jservice.io/api/random', function(data){
$('#question').html(data[0].question);
this.answer = data[0].answer.toLowerCase();
});
},

checkAnswer: function() {
if($('#answer').val() === this.answer) {
this.score += 1;
}
}
}

Quiz.init();
});

})(window);

Answer

Because you are nesting inside another function, the this context changes to that function, so the methods you look for are no longer available. You can try to solve it by either storing the this inside a variable that will be within the scope of the function you are defining, or by using Double Arrow Functions, which have no associated this context themselves (and therefor also don't support bind or call). Here are your options:

Declare a variable:

skipQuestion: function() {
    var that = this;
    $('#skip').click(function(){
        that.getQuestion();
    })
}

or a Double Arrow Function:

skipQuestion: function() {
    var that = this;
    $('#skip').click(() =>  that.getQuestion())
}

Your init function is considered a method of your Quiz object, while the anonymous function passed to the click event is not a method of your Quiz, it is a method of an anonymous object created in the background, and shares no methods or variables with your Quiz. This is important to consider!