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; }; })();