Encapsulation in JavaScript
encapsulation) is an important principle of software design
essentially it means:
Keep similar things together; keep different things apart.
Two related and overlapping concepts are information hiding and decomposition).
Why encapsulate?
- keep code and the data it uses together
- limit state mutations (to a single file or a contiguous block of code)
- limit reach of bugs
-
increase cohesion of data & the code that loves it
-
decrease coupling of unrelated program features
- focus on one thing at a time
- so you know where in your code to look
"Do one thing, and do it well" is the encapsulator's motto
Encapsulation is for Humans
Remember, the computer doesn't care about your fancy design, but humans will, so keep it simple.
OO?
Encapsulation is an important part of object-oriented design
but it's not the only part (there's also inheritance, polymorphism, interfaces, etc.)
and you can use encapsulation on its own
Encapsulation Technique 1: closure scope
Here's a factory function that creates & returns a circle object:
function createCircle(radius) {
return {
area: function() {
return radius * radius * Math.PI;
}
}
};
let circle = createCircle(3);
console.log("Area is " + circle.area());
console.log("Radius is " + circle.radius); // THIS WILL FAIL
-
In the above code, radius
is only visible inside the scope of the function createCircle
.
- This is normal; any parameter or local variable is only visible inside its function.
- It's also visible inside the
area
function since that function is defined inside the function createCircle
.
-
area
is a property on the hash (JS object) that is returned by createCircle
- This means that
area
is visible to the caller of createCircle
So, area
is exposed but radius
is hidden. In other words...
radius
is encapsulated inside circle
Encapsulation Technique 2: private variables
private variables are encapsulated inside a closure:
function createCircle(radius) {
let diameter = radius * 2;
return {
area: function() {
return radius * radius * Math.PI;
},
circumference: function() {
return diameter * Math.PI;
}
}
};
let circle = createCircle(3);
console.log("Area is " + circle.area());
Note that only area
and circumference
are exposed via a pointer to the circle; diameter
and radius
are private.
Encapsulation Technique 3: IIFE
- The following cryptic syntax is very common in JS
- It's essentially the same as the previous code, but combining two steps into one
- It's called an IIFE = Immediately Invoked Function Expression
(function(){ })();
Expanded:
( function() { ... } ) ();
↑ ↑ ↑
define ↑ invoke
execute
The trick is, when you invoke the function, you generate a new scope for that invocation's closure.
You then preserve that scope by returning a pointer to an object that you created inside that closure.
Encapsulation with IIFE Example
Example:
let circle = (function(radius) {
let diameter = radius * 2;
return {
area: function() {
return radius * radius * Math.PI;
},
circumference: function() {
return diameter * Math.PI;
}
}
})(3);
console.log("Area is " + circle.area());
https://developer.mozilla.org/en-US/docs/Glossary/IIFE