Basic Javascript Patterns
Javascript is quite a loose language, its possible to do things in a bunch of different ways. This tends to lead to developers coding themselves into a corner with custom patterns that seem clunky.
Below are a few of the patterns that are often seen in Javascript development, use these as a reference if you’re unsure about how to write a Javascript module.
The module.exports property and the require function are found in either Node.js or Browserify, I will follow up with a separate post on how to use Browserify to organise your client-side scripts.
Class Pattern
Javascript isn’t a class-based language, its a prototypal language. However, it can behave in similar ways - just try to remember that this isn’t C#, it has its own behavior. What you may consider as WTFs are probably in line with the language specification.
var Hello = (function() {
// this is our object prototype and constructor
function Hello(name) {
this.name = name;
}
// this is a "static" function
Hello.foo = function() {
return "fuzzed up, " + this.name;
};
// this is an instance function
Hello.prototype.bar = function() {
return "beyond all repair, " + this.name;
};
// this is a private function
var snafu = function() {
return "situation normal, " + this.name;
};
// return the object prototype from the closure
return Hello;
})();
module.exports = Hello;
// Usage in another module
var Hello = require('./Hello');
var hello = new Hello('Gunty McSquintlock');
console.log(Hello.foo()); // "fuzzed up, Hello" <- That's the name of the factory function!
console.log(hello.bar()); // "beyond all repair, Gunty McSquintlock"
console.log(hello.foo()); // error - not on the instance
console.log(hello.snafu()); // error - private
Module Pattern
In this pattern, private functions are declared inside the factory function and public functions are returned inside an object literal.
// this is our factory
var Hello = function(name) {
// this is a private function
var snafu = function() {
return 'situation normal, ' + name;
};
return {
// this is an instance function
bar: function() {
return 'beyond all repair, ' + name;
}
};
};
// this is a "static" function
Hello.foo = function() {
return 'fuzzed up, ' + this.name;
};
module.exports = Hello;
// Usage in another module
var Hello = require('./Hello');
var hello = Hello('Gunty McSquintlock');
console.log(Hello.foo()); // "fuzzed up, " <- Not inside a factory function, so there isn't a name!
console.log(hello.bar()); // "beyond all repair, Gunty McSquintlock"
console.log(hello.foo()); // error - not on the instance
console.log(hello.snafu()); // error - private
Revealing Module Pattern
This is similar to the Module Pattern, except every instance function starts life as a private function and then we decide which ones to reveal to the public return object.
// this is our factory
var Hello = function(name) {
// this is a private function
var snafu = function() {
return 'situation normal, ' + name;
};
// this *will* be an instance function, but looks like a private now
var bar = function() {
return 'beyond all repair, ' + name;
};
return {
// reveal the instance function
bar: bar
};
};
// this is a "static" function
Hello.foo = function() {
return 'fuzzed up, ' + this.name;
};
module.exports = Hello;
// Usage in another module
var Hello = require('./Hello');
var hello = Hello('Gunty McSquintlock');
console.log(Hello.foo()); // "fuzzed up, " <- Not inside a factory function, so there isn't a name!
console.log(hello.bar()); // "beyond all repair, Gunty McSquintlock"
console.log(hello.foo()); // error - not on the instance
console.log(hello.snafu()); // error - private
The Coffeescript Version
I like Coffeescript, here are the Hello.js files in Coffeescript.
Class Pattern
# this is our class
class Hello
# constructor
constructor: (@name) ->
# "static" function
@foo: -> 'fuzzed up, ' + @name
# instance function
bar: -> 'beyond all repair, ' + @name
# private function
snafu = -> 'situation normal, ' + @name
module.exports = Hello
Module Pattern
# this is our factory
Hello = (name) ->
# this is a private function
snafu = -> 'situation normal, ' + name
return {
# this is an instance function
bar: -> 'beyond all repair, ' + name
}
# this is a "static" function
Hello.foo = -> 'fuzzed up, ' + @name
module.exports = Hello
Revealing Module Pattern
# this is our factory
Hello = (name) ->
# this is a private function
snafu = -> 'situation normal, ' + name
# this *will* be an instance function, but looks like a private now
bar = -> 'beyond all repair, ' + name
return {
# reveal the instance function
bar: bar
}
# this is a "static" function
Hello.foo = -> 'fuzzed up, ' + @name
module.exports = Hello