Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Instantiatable Objects & Constructors

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

Ok ok, it's finally time to talk about the JavaScript elephant in the room: prototypical inheritance. This means, real JavaScript objects that we can instantiate!

But first, let's do just a little bit of reorganization on Helper - it'll make our next step easier to understand.

Instead of putting all of my functions directly inside my object immediately, I'll just say var Helper = {}:

... lines 1 - 2
(function(window, $) {
... lines 4 - 54
/**
* A "private" object
*/
var Helper = {};
... lines 59 - 71
})(window, jQuery);

Then set the Helper.initialize key to a function, and Helper.calculateTotalWeight equal to its function:

... lines 1 - 2
(function(window, $) {
... lines 4 - 54
/**
* A "private" object
*/
var Helper = {};
Helper.initialize = function ($wrapper) {
... line 61
};
Helper.calculateTotalWeight = function() {
... lines 64 - 69
};
})(window, jQuery);

This didn't change anything: it's just a different way of putting keys onto an object.

Everything is Awesome (an Object)!

Ok, in JavaScript, everything is an object, and this is quite different than PHP. Obviously, Helper is an object. But we already saw earlier that functions are also objects. This means when we say this.handleRepLogDelete - which references a function - we can call some method on it called bind().

Heck, even strings are objects: we'll see that in a moment. The only downside with our Helper or RepLogApp objects so far is that they are effectively static.

The Goal: Non-Static Objects

Why? Because, there can only ever be one Helper object. If I had two areas on my page, and I wanted to calculate the total weight in each, we'd be in trouble! If we called initialize() a second time for the second area, it would override the original $wrapper property. It acts like a static object. And that's what we need to fix: I want to be able to instantiate objects... just like we do in PHP with the new keyword. This will let us create two Helper instances, each with their own $wrapper property.

Creating your Constructor

How do we do that? Instead of setting Helper to {}, set it to a function. Let's set Helper to what was our initialize() method:

... lines 1 - 2
(function(window, $) {
... lines 4 - 54
/**
* A "private" object
*/
var Helper = function ($wrapper) {
this.$wrapper = $wrapper;
};
... lines 61 - 69
})(window, jQuery);

Huh. So now, Helper is a function... But remember that functions are objects, so it's totally valid to add properties or methods to it.

Why would set our object to a function? Because now we are allowed to say this.helper = new Helper($wrapper):

... lines 1 - 2
(function(window, $) {
window.RepLogApp = {
initialize: function ($wrapper) {
this.$wrapper = $wrapper;
this.helper = new Helper(this.$wrapper);
... lines 8 - 16
},
... lines 18 - 52
};
... lines 54 - 69
})(window, jQuery);

JavaScript does have the new keyword just like PHP! And you can use it once Helper is actually a function. This returns a new instance of Helper, which we set on a property.

In PHP, when you say new Helper(), PHP calls the constructor on your object, if you have one. The same happens here, the function is the constructor. At this point, we could create multiple Helper instances, each with their own $wrapper.

Now, instead of using Helper in a static kind of way, we use its instance: this.helper:

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

Before we keep celebrating, let's try this. Go back, refresh, and delete one of our items! Huh, it worked... but the total didn't update. And, we have an error:

Uncaught TypeError: this.helper.calculateTotalWeight is not a function

That's odd! Why does it think our Helper doesn't have that key? The answer is all about the prototype.

Leave a comment!

4
Login or Register to join the conversation
Graymath technology Avatar
Graymath technology Avatar Graymath technology | posted 4 years ago

just curious if we passed ($wrapper) instead of (this.$wrapper) in
this.helper = new Helper(this.$wrapper);

would it make any difference.

Reply

Hey Abdul,

Haha, yeah, a tricky question :) Actually, it won't make any difference, but since we set that variable on a property, it makes sense to use the property further to be consistent.

Cheers!

Reply
Default user avatar

Why You didn't add calculateTotalWeight function inside the constructor?
like:
var Helper = function($wrapper) {
this.$wrapper = $wrapper

this.calculateTotalWeight = function(){
var totalWeight = 0;
this.$wrapper.find('tbody tr').each(function() {
totalWeight += $(this).data('weight');
});

return totalWeight;
};
};

Reply

Hey Andrew!

In this case is not needed, because at this point we only update total weight whenever a row is deleted or added not when initializing the application.

Have a nice day

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