Buy
Buy

The Object prototype!

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

In RepLogApp, when we try to call this.helper.calculateTotalWeight, for some reason, it doesn't think this is a function!

... lines 1 - 2
(function(window, $) {
window.RepLogApp = {
... lines 5 - 17
updateTotalWeightLifted: function () {
this.$wrapper.find('.js-total-weight').html(
this.helper.calculateTotalWeight()
);
},
... lines 23 - 52
};
... lines 54 - 69
})(window, jQuery);

But down below, we can plainly see: calculateTotalWeight is a function! What the heck is going on?

To find out, in initialize, let's log a few things: console.log(this.helper) and then Object.keys(this.helper):

... lines 1 - 2
(function(window, $) {
window.RepLogApp = {
initialize: function ($wrapper) {
... line 6
this.helper = new Helper(this.$wrapper);
console.log(this.helper, Object.keys(this.helper));
... lines 9 - 18
},
... lines 20 - 54
};
... lines 56 - 71
})(window, jQuery);

The Object.keys method is an easy way to print the properties and methods inside an object.

Comparing the Helper object and new Helper instance

Do the same thing for Helper and Object.keys(Helper):

... lines 1 - 2
(function(window, $) {
window.RepLogApp = {
initialize: function ($wrapper) {
... line 6
this.helper = new Helper(this.$wrapper);
console.log(this.helper, Object.keys(this.helper));
console.log(Helper, Object.keys(Helper));
... lines 10 - 18
},
... lines 20 - 54
};
... lines 56 - 71
})(window, jQuery);

Let's look at what the difference is between our instance of the Helper object and the Helper object itself.

Ok, find your browser, refresh, and check this out! There's the helper instance object, but check out the methods and properties on it: it has $wrapper. Wait, so when we create a new Helper(), that instance object does have the $wrapper property... but somehow it does not have a calculateTotalWeight method!

That's why we're getting the error. The question is why? Below, where we printed the upper-case "H" Helper object, it prints out as a function, but in its keys, it does have one called calculateTotalWeight. Oooh, mystery!

This can be very confusing. So follow this next part closely and all the way to the end.

At this point, the calculateTotalWeight function is effectively still static. The only way that we can call that method is by saying Helper.calculateTotalWeight - by calling the method on the original, static object. We cannot call this method on the instantiated instance: we can't say this.helper.calculateTotalWeight(). It just doesn't work!

Introducing the Prototype

To fix this, instead of adding the method via Helper.calculateTotalWeight, we need to say Helper.prototype.calculateTotalWeight:

... lines 1 - 2
(function(window, $) {
... lines 4 - 63
Helper.prototype.calculateTotalWeight = function() {
... lines 65 - 70
};
})(window, jQuery);

That weird little trick fixes everything. To test it easily, back up in initialize(), let's try calling this.helper.calculateTotalWeight():

... lines 1 - 2
(function(window, $) {
window.RepLogApp = {
initialize: function ($wrapper) {
... line 6
this.helper = new Helper(this.$wrapper);
console.log(this.helper, Object.keys(this.helper));
console.log(Helper, Object.keys(Helper));
console.log(this.helper.calculateTotalWeight());
... lines 11 - 19
},
... lines 21 - 55
};
... lines 57 - 72
})(window, jQuery);

This did not work before, but refresh! 157.5 - it works now!

The short explanation is that when you create objects that need to be instantiated, you need to add its properties and methods to this special prototype key.

Once you've done that and create a new Helper, magically, anything on the prototype, like calculateTotalWeight, becomes part of that object.

But, that superficial explanation is crap! Let's find out how this really works!

Leave a comment!

  • 2019-02-15 Diego Aguiar

    Hmm, so this.$text inside of Helper.btnAppear is undefined? It makes no sense. What happens if you do this


    var Helper = function ($text) {
    this.$text = 'hi';
    };

    Helper.prototype.btnAppear = function () {
    console.log(this.$text);
    };

    Does it still says undefined? If that's the case I'm not sure what's going on, probably the browser where you are running your JS does not support the prototype? Anyways, if you can't find the solution just declare the "btnAppear" function inside the Helper constructor


    var Helper = function ($text) {
    ...
    this.btnAppear = function() {
    // do your thing.
    }
    };

    Cheers!

  • 2019-02-14 Rosoam

    I did a check -


    var Helper = function ($text) {
    this.$text = $text;
    console.log(this.$text); // --> return : Object { 0: p.text, length: 1, prevObject: Object(1) }
    };


    BUT


    Helper.prototype.btnAppear = function () {
    this.$text.fadeToggle(); // --> return : TypeError: this.$text is undefined
    };

  • 2019-02-14 Rosoam

    Here it is : Object { 0: p.text, length: 1, prevObject: Object(1) }

  • 2019-02-13 Diego Aguiar

    Hey Rosoam

    Hmm, your code looks good. Can you double check what is returning $('.text')

  • 2019-02-13 Rosoam

    Hi, I have a problem using my Helper.prototype.btnAppear function -> "TypeError: this.$text is undefined" .

    window.Appear = {
    initialize:function () {
    this.$btn = $('.btn');
    this.$text = $('.text');
    this.helper = new Helper(this.$text);
    this.$btn.on('click', this.helper.btnAppear);
    },
    };

    var Helper = function ($text) {
    this.$text = $text;
    };

    Helper.prototype.btnAppear = function () {
    this.$text.fadeToggle(); // --> this.$text create an error, when the function is called by the Appear object event
    };

    Could someone please tell me if something is wrong here ?

    Thank's a lot!

  • 2017-12-14 Serge Boyko

    OMG, that must be the clearest explanation of JS prototypes I've ever seen! You're the best! (as always)