Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

The Object prototype!

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

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!

6
Login or Register to join the conversation
RSO Avatar

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!

Reply
MolloKhan Avatar MolloKhan | SFCASTS | RSO | posted 4 years ago | edited

Hey RSO

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

Reply
RSO Avatar
RSO Avatar RSO | MolloKhan | posted 4 years ago | edited

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

};
`

Reply
RSO Avatar
RSO Avatar RSO | MolloKhan | posted 4 years ago | edited

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

Reply
MolloKhan Avatar MolloKhan | SFCASTS | RSO | posted 4 years ago | edited

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!

Reply

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

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial uses an older version of Symfony... but since it's a JavaScript tutorial, the concepts are still ? valid!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": "^7.2.0",
        "symfony/symfony": "3.1.*", // v3.1.10
        "twig/twig": "2.10.*", // v2.10.0
        "doctrine/orm": "^2.5", // v2.7.1
        "doctrine/doctrine-bundle": "^1.6", // 1.10.3
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
        "symfony/swiftmailer-bundle": "^2.3", // v2.4.0
        "symfony/monolog-bundle": "^2.8", // 2.12.0
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "friendsofsymfony/user-bundle": "~2.0@dev", // dev-master
        "doctrine/doctrine-fixtures-bundle": "~2.3", // v2.4.1
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.1
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "friendsofsymfony/jsrouting-bundle": "^1.6" // 1.6.0
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.1.1
        "symfony/phpunit-bridge": "^3.0" // v3.1.6
    }
}
userVoice