user6002037
user6002037

Reputation:

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);

Upvotes: 0

Views: 134

Answers (2)

somethinghere
somethinghere

Reputation: 17340

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!

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281686

The thing is you are using this inside the click event and it refers to the event rather than you context. To work around you need to assign this to another variable and then use that;

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

            })
        },

$.get and .click event create their own context and thus this refers to their context instead of the context of quiz.

JS

(function(window){

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

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

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

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

                })
            },

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

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

        Quiz.init();
    });

})(window);

Upvotes: 0

Related Questions