The Object prototype!

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

71 lines web/assets/js/RepLogApp.js
... 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):

73 lines web/assets/js/RepLogApp.js
... 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):

73 lines web/assets/js/RepLogApp.js
... 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:

74 lines web/assets/js/RepLogApp.js
... 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():

74 lines web/assets/js/RepLogApp.js
... 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!