Hey. Let’s talk about JavaScript module patterns. They’re a lot of fun.
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log('My Name is ' + this.name);
}
var person = new Person('Joel');
person.sayName(); // 'My Name is Joel'
Probably the most widely used pattern is the Prototype pattern. Prototypes are JavaScripts way of handling inheritance, and without going too much into that, it’s the built-in way for objects to share and inherit methods.
There are some great reasons to use the Prototype pattern:
Some issues arise, however, because of the keyword this
.
// Setup a EventHandler
function EventHandler(firedText) {
this.firedText = firedText;
}
EventHandler.prototype.handleClick = function(e) {
console.log(this.firedText);
}
var eventHandler = new EventHandler('fired!');
window.addEventListener('click', eventHandler.handleClick);
In the funciton constructor, we accept a string firedText
that we attach to this
. However, when we attach the event to the window object, the this
reference changes from being a reference to EventHandler
to now being a reference to window
. There is a way around this behaviour, however it’s only supported in ES5 browsers:
// Setup a EventHandler
function EventHandler(firedText) {
this.firedText = firedText;
}
EventHandler.prototype.handleClick = function(e) {
console.log(this.firedText);
}
var eventHandler = new EventHandler('fired!');
window.addEventListener('click', eventHandler.handleClick.bind(eventHandler));
.bind
is a subject for another post, but in short it makes the this
reference whatever you pass into it, which in this case is eventHandler
as we previously had assumed.
function Person(name) {
function sayName() {
console.log(name);
}
return {
sayName: sayName
};
}
var person = new Person('Joel');
person.sayName(); // Joel
The closure pattern operates by utilizing closures (shockingly), or simply the fact that variables referenced outside a function (and are used IN that function) “hang” around after context passes. In this case, the name
argument is still present even after we’ve executed the Person
constructor.
Some nice things about this pattern:
this
anywhere, which means no more .bind
!However this comes at a cost: no prototypes. Since the object we return is the instance object, there isn’t a great place to append prototype methods. Also, this method of modularizing can be dangerous when generating and keeping track of state as all our references are in a closure (and thus hard to null
ify).
var person = {
setName: function(name) {
this.name = name;
},
sayName: function() {
console.log(this.name);
}
};
var joel = Object.create(person);
joel.setName('Joel');
joel.sayName(); // 'Joel'
Sharing some traits with prior patterns, the object literal pattern uses an ES5 method Object.create
which accepts takes an object and create’s a new one, with the object argument being set as it’s prototype. This is, essentially, a direct replacement for using the new
keyword to create an instance.
Obviously, there are some drawbacks, namely the this
keyword being present inside methods. Because of that, there be issues using this pattern when assinging events on the window
object.
This also is somewhat confusing to folks transitioning from classical languages, as there is no new
to be found. However, this is more-or-less the ‘JavaScript’ way of doing inheritance, and reflects that in it’s syntax.
class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
var joel = new Person('Joel');
joel.sayName(); // 'Joel'
The next version of JavaScript introduces the class
keyword and code encapsulation. This also comes with extend
, but is a subject for yet-another-post.
Some nice things from this:
constructor
makes it clear what is doing construction… obviously.There are still some issues with the format: The first being that this
is still an issue. Also, it forces the developer to write code that’s more single-inheritance oriented. Which isn’t a huge issue, but breaks from the power and flexibility that prototypes offer.
These are just a few of the modules patterns I’ve seen in the wild, and it’s easy enough to mix and match them. I’d be curious to know what you’re using and why, so sound off. We are on the internet, you know.