Object Literals and ze Module Pattern
What are Object Literals?
Object Literals are literally JUST objects.
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
- Both use {} to define scope but a function must have the function keyword
- An object literal will never have a var keyword unless a function is defined as a property
- Equal signs and semi-colons on the end of lines also an indicator
Object literals DO have context and this and can have functions as values
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);
}
};
Remember an Object is simply a sequence of keys and values or key-value pairs separated by commas.
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);
};
You can also add additional keys or properties to an object outside it's definition
The Module Pattern
Your very first design pattern
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.
The Module Pattern
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 vs. Object Literal
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});
Mix-ins or Dependency Injection
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;
})();
Revealing Module Pattern
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
};
})();
Revealing Module Pattern
The Solution
All functions/variables are private and interact with each other without object reference notation and only expose(reveal) pointers.
Module Pattern vs. Revealing Module Pattern
Solution:
Use what you prefer and know why you chose it.
After all they're just patterns.
Things to Remember
-
This is a good way to implement encapsulation or private variables.
-
You cannot access private members in methods that are added to the object later.
-
You cannot write tests for private members directly.
-
Because our object was created in a function we are persisting state with a closure.
Additional Resources
deck
By Jason Sewell
deck
- 2,097