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