The goal is to create an object where only SOME of the properties and methods are public (able to be accessed by other parts of the program) and the rest of the properties and methods are private (aka "internal", cannot be accessed from outside).
Here's the general idea:
person = {
private properties: {
stomach,
brain,
heart
}
Private methods: {
circulateBlood()
digestFood()
}
public properties and methods: {
mouth,
ears,
hands,
feet,
nose,
eyes,
see()
eat(),
speak(),
listen(),
smell()
}
}
^^ In this case, invoking person.see()
should do something, but we should not be able to call person.digestFood()
or set the value of person.stomach
.
We have to use something called an IIFE (Immediately Invoked Function Expression). This is basically a hack where we force the JavaScript engine to immediately run an anonymous function, and return it. Because the function is anonymous it cannot be called again; and because it is returned immediately, only what is inside the return block can be accessed by the rest of the program.
Start with an anonymous function:
function () {
let x = 2
return x*2
}
// Returns 4
The way to make this into an IIFE is:
- Write a generic invocation statement like
myFunction()
- Wrap that function name in parentheses like so
(myFunction)()
- Paste over the inside of those parentheses with your anonymous function definition.
The end result should look something like this:
(function() {
let x = 2;
return x * 2;
})();
// Returns 4 *immediately*
^^ This is a super-basic IIFE. When the JavaScript interpreter sees this, it will invoke the function immediately and execute the return statement.
This won't do much for us yet, but notice that you can assign a variable equal to this IIFE:
let newVariable = (function() {
let x = 2;
return x * 2;
})();
// ^^ This assigns a value of 4 to newVariable
Now we're getting somewhere.
Here's how you would do it:
let myModule = (function () {
// PRIVATE section of the module (above the return block)
// You can set up any internal functions and variables you like:
// Create a private number with value between 0 and 5:
let privateNum = Math.random()*5;
// Create a private function that squares the number:
function () squarePrivate{
privateNum *= privateNum;
}
// Run the square function:
squarePrivate();
// PUBLIC section of the module is everything inside the RETURN OBJECT:
return {
// A method that returns the value of the private number
whatIsTheNum: function(){
return privateNum;
},
// A method that subtracts 2 from the private number
reduceTheNum: function(){
privateNum -= 2;
}
}
})()
-
Runs your anonymous function.
-
Sets
myModule
equal to everything inside the IIFE'sreturn
statement.
-
You can access all public properties and methods of
myModule
. For instance, you can invokemyModule.whatIsTheNum()
and it will return the internal value ofprivateNum
. -
You cannot directly call the module's private methods. E.g. you cannot invoke
myModule.squarePrivate()
<--- that will returnundefined
and do nothing. -
You also cannot directly access the module's private properties, meaning you cannot access
myModule.privateNum
. Again, that will returnundefined
.
Notice a couple other things about the example above:
-
It is entirely up to the coder whether private elements are accessible, or how. In this case we allowed
whatIsTheNum
to return the value of a private property, but that is certainly not required. You can lock it up as tightly as you want. -
Notice that our public methods are using the magic of closures to interact with the private properties inside the module. What is this magic, again? The magic part is that our public methods are able to interact with private variables inside an anonymous function which already finished running! That's fuckin weird! But closures allow us to do that. When those public methods are returned, they close over all the private internals that were available at the time the IIFE executed. Because of that, we can still interact with those 'internals' later.
JavaScript Design Patterns (Addy Osmani) The Module Pattern https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript