Joe Karlsson
progress. tech. cats. coffee. art. food. photog. mpls.
No fancy OOP, or closures, it's just {}
You can only EVER have one instance of an object using an object literal
You don't use the function keyword to define an object literal
//Object literal
var myObject = {};
var myInformation = {
name: "Jason",
age: 82,
alias: "jaywon"
};
//NOT AN Object literal
var myFunction = function(){};
var myInformation = function(){
var name = "Jason";
var age = 82;
var alias = "jaywon";
};
Object Literal
Function Expression
var calculator = {
total: 0,
name: "TI-85",
clear: function(){
this.total = 0;
},
add: function(num){
this.total += num;
},
subtract: function(num){
this.total -= num;
},
square: function(num){
this.total = Math.sqrt(num);
}
};
var calculator = {
total: 0,
name: "TI-85",
clear: function(){
this.total = 0;
}
};
calculator.serialNumber = "JSK245EE";
calculator.add = function(num){
this.total += num;
};
calculator.subtract = function(num){
this.total -= num;
};
calculator.square = function(num){
this.total = Math.sqrt(num);
};
The Module Pattern can be thought of a way to implement "privacy" on our object literals, or private and public properties using closures.
We can still only ever have one instance of an object using this pattern just like an object literal.
The Module Pattern allows us "class like" benefits and keeps parts of our object out of the global scope.
With the Module Pattern we protect certain properties of our object and only return(expose) certain properties.
This can be thought of as an API for your object and the properties our object is returning is known as it's interface.
The values of the private properties are protected and kept alive within the closure.
The practice of protecting or keeping values private/protected is known as encapsulation.
The Module Pattern uses an Immediately-Invoked Function Expression(IIFE) to return an object literal.
We still cannot call new on our object.
What we have access to looks and behaves very much the same as an object literal.
We can still only have 1 instance of this object.
It's just how we created it that changed.
It's just a function that returns an object to our variable.
var myObject = {
name: "Jason",
getName: function(){
return this.name;
}
};
// We can access ALL properties/members
// of an object
myObject.name = "Jon";
myObject.getName(); // "Jon"
Object Literal
var myObject = (function(){
var name = "Jason";
return {
age: 23,
getName: function(){
return name;
}
};
})();
// We can access only exposed
// properties/members of an object
myObject.age = 75; // 75
//does not change internal name
myObject.name = "Jon";
myObject.getName(); // "Jason"
Module Pattern
myObject is an Object
myObject is an Object
var mySecretModule = (function () {
//private variables
var module = {};
var privateSecret;
//public variables
module.publicSecret = "I like Tegan and Sara.";
//public methods
module.protectSecret = function(secret) {
privateSecret = secret;
console.log("Your secret is safe.");
};
return module; //return the object literal we created
})();
mySecretModule.protectSecret("I like clowns."); // "Your secret is safe";
console.log(mySecretModule.privateSecret); //undefined
console.log(mySecretModule.publicSecret); // "I like Tegan and Sara."
You can create your object before your return for greater readability.
var mySecretModule = (function ($, config) {
var module = {};
module.findDomElement = function(){
return $('#someIdentifier');
}
module.doSomeImportantThings = function() {
if(config && !config.production){
console.log('some testing variables');
}
};
return module; //return the object literal we created
})(jQuery, {production:true});
This is a way for us to pass in variables to our modules that they depend on without having to depend on global scope or naming convention.
Our module is now dependent on the internal existence of those objects but not the external implementation
var mySecretModule = (function () {
//private variables
var module = {};
var privateSecret;
//public variables
module.publicSecret = "I like Tegan and Sara.";
//public methods
module.protectSecret = function(secret) {
privateSecret = secret;
console.log("Your secret is safe.");
};
module.changePublicSecret = function(secret) {
module.publicSecret = secret; // <----- EWWWWWW
};
return module;
})();
The Problem
Access to other variables/functions in module must be prefaced with module name which can be cumbersome
var mySecretModule = (function () {
//ALL variables are private
var privateSecret;
var publicSecret = "I like Tegan and Sara.";
//All methods are private
function protectSecret(secret) {
privateSecret = secret;
console.log("Your secret is safe.");
}
function getPublicSecret(){
return publicSecret;
}
function changePublicSecret(secret) {
publicSecret = secret;
}
//REVEAL only what you want to be public
return {
getSecret: getPublicSecret,
protectSecret: protectSecret,
changeSecret: changePublicSecret
};
})();
The Solution
All functions/variables are private and interact with each other without object reference notation and only expose(reveal) pointers.
Solution:
Use what you prefer and know why you chose it.
After all they're just patterns.
By Joe Karlsson
An exploration of object literals and the Module Pattern and their likenesses and differences and applications.