Some Notes from a discussion of encapsulation in JavaScript
The topic of encapsulation in JavaScript came up in our bi-weekly technologists group recently. First question was, what is encapsulation and why is it a good thing. The first obvious benefit is the elimination of global values.
An example with global variables. TAX_RATE is vulnerable; it is a global variable that can be overwritten.
// Not Best Practice. Relies on Global variables and functions.
var TAX_RATE = 0.07;
function calculateTotalPrice(basePrice) {
return basePrice + (basePrice * TAX_RATE);
}
function calcPrice () {
var basePrice = document.getElementById('ex1_basePrice').value;
basePrice = basePrice - 0; // cast to integer
var totalPrice = calculateTotalPrice(basePrice);
document.getElementById('ex1_totalPrice').value = totalPrice;
}
The problem with the global variable, or course, is that anything can come along a modify it. In this HTML example, click Calculate Price. Then open a console window (Use Firebug or Developer Tools) and alter this global variable:
> TAX_RATE = 1.00;
Now click Calculate Price. It would be just as easy to overwrite the global functions to produce different values:
> calcPrice = function() { return 1; }
Now our price calculation is completely re-written.
One practice to prevent the collision of global variables is to organize them in a single global variable:
var myApp = {
TAX_RATE: 0.08,
calculateTotalPrice: function(basePrice) {
return basePrice + (basePrice * this.TAX_RATE);
},
calcPrice: function() {
var basePrice = document.getElementById('ex3_basePrice').value;
basePrice = basePrice - 0;
var totalPrice = myApp.calculateTotalPrice(basePrice);
document.getElementById('ex3_totalPrice').value = totalPrice;
}
};
This works, but it can still leave myApp vulnerable. myApp.TAX_RATE is still globally accessible.
Using encapsulation, it is possible to create protected members.
var calcPrice2 = (function() {
// private
var PRIVATE_TAX_RATE = 0.05;
function calculateTotalPrice2(basePrice) {
return basePrice + (basePrice * PRIVATE_TAX_RATE);
}
// public
return function() {
var basePrice = document.getElementById('ex2_basePrice').value;
basePrice = basePrice - 0;
var totalPrice = calculateTotalPrice2(basePrice);
document.getElementById('ex2_totalPrice').value = totalPrice;
};
})();