Wednesday, 24 July 2013

Structuring your Javascript code - Revealing prototype pattern and namespaces

Creating Spaghetti-code in Javascript is not difficult. There are no clear pattern in Javascript for encapsulation for novice developers of Javascript, unless you really are familiar with what is possible with Javascript. Most developers learn Javascript in an ad-hoc manner, just adding functions to a Javascript file and keep on adding code to their monolithic design until they realize that a pattern must be used to structure the Javascript code. Of course, today, with the huge focus on Javascript, there are multiple patterns to follow and coding Javascript is a more mature topic that it used to be. There are four designs which we can choose when we structure our code (possible more):
  • Module pattern
  • Prototype pattern
  • Revealing module pattern
  • Revealing prototype pattern
We will in this article focus on the last, the revealing prototype pattern. This pattern allows refactoring the Javascript code, i.e. extensibility, and it also offers encapsulation. It is the most flexible and still rigid solution. It is not difficult to understand either, once you see an example which I will present next. In our example, we use LocalStorage, which is allows saving data on the client side through the browser. It is quicker and safer than ordinary cookies. We will encapsulate the logic of saving to the LocalStorage with a simple class-like structure in Javascript. Of course, I could have used TypeScript here and just create a class, but this article is more focused about explaining the concepts so you can recognize this pattern when you read Javascript code later on that uses this pattern and understand what is going on. Let's look at the Javascript class following the revealing prototype pattern next:

var AppUtils = AppUtils || {}; 

AppUtils.LocalStorageUtility = function(storageKeys, sourceElements, feedbackElement) {
    this.storageKeys = storageKeys;
    this.sourceElements = sourceElements; 
    this.feedbackElement = feedbackElement;
};

AppUtils.LocalStorageUtility.prototype = (function () {

        var storeSettings = function (thisObj) {
            for (var i = 0; i < thisObj.storageKeys.length; i++) {
                var storageKey = thisObj.storageKeys[i]; 
                var elementName = thisObj.sourceElements[i];
                localStorage.setItem(storageKey, $("#" + elementName).val());  
            }
            $("#" + thisObj.feedbackElement).text("Local setting saved!");
        },
        loadSettings = function (thisObj) {

            for (var i = 0; i < thisObj.storageKeys.length; i++) {
                var storageKey = thisObj.storageKeys[i]; 
                var elementName = thisObj.sourceElements[i];
                $("#" + elementName).val(localStorage.getItem(storageKey)); 
            }

            $("#" + thisObj.feedbackElement).text("Local setting loaded!");
        },
        clearSettings = function () {
            localStorage.clear(); 
        },
         hasLocalStorage = function () {
            return typeof (Storage) !== "undefined"; 
        }

        return {
            StoreSettings: storeSettings,
            LoadSettings: loadSettings,
            ClearSettings: clearSettings,
            HasLocalStorage: hasLocalStorage
        };

})(); 

The consumer of this class-like structure in Javascript will provide two string arrays which is the local storage key names and the elements to read and store local storage values from. I do not do any checking here that the two arrays are the same length or that they are of the correct type (arrays preferably with string of course). This is what TypeScript version of this code would specify. Remember, TypeScript is much easier to use than manually creating class like structs like we do here, but the concepts are anyways important to understand. In the revealing prototype pattern we return an object literal and the public part is exposed here, i.e. the revealing prototype. In addition, we call it revealing because the prototype is self invoking. The private parts are what is outside of the return statement above. We point to the private methods, and this is fine, and we alias them to a capitalized version to let the user call into the private methods. If we want public fields We also need a GUI for the Javascript code here:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Localstorage demo</title>
</head>

<script src="Scripts/jquery-2.0.3.min.js"></script>
    <script src="Scripts/LocalStorageUtility.js"></script>
    
    <script type="text/javascript">

        $(document).ready(function () {
            var ls = new AppUtils.LocalStorageUtility(["Name", "City"], ["tbName", "tbCity"], "lblFeedback"); 

            if (ls.HasLocalStorage) {
                $("#lblFeedback").text("Local storage is enabled!"); 
            }
            else {
                $("#lblFeedback").text("Local storage is disabled!"); 
            }

            $("#btnLoadSettings").click(function () { ls.LoadSettings(ls); }); 
            $("#btnSaveSettings").click(function () { ls.StoreSettings(ls); }); 
            $("#btnClearSettings").click(ls.ClearSettings); 
        }); 

    </script>

<body>

    <table>
        <tr>
            <td>Name</td><td><input id="tbName" type="text" /></td>
            <td>City</td><td><input id="tbCity" type="text" /></td>
        </tr>
    </table>
  
    <button id="btnLoadSettings" type="button">Load settings</button>

    <button id="btnSaveSettings" type="button">Save settings</button>

    <button id="btnClearSettings" type="button">Clear settings</button>    

    <p id="lblFeedback" style="color: darkgreen">ready</p>

</body>
</html>


As you can see, with this pattern we must keep track of the this pointer in the prototype definition. There are alternatives, such as bind, and call, but I wanted to keep the example clear. In the jQuery load method above we define click handlers that pass in the instance of the LocalStorageUtility, which we have instantiated, such that the prototype gets the correct instance. As you perhaps know, the prototype must bind to the correct this pointer, and here we explicitly pass it in (i.e. the instance of LocalStorageUtility). Finally, note that we define a namespace here with the "or empty object literal" technique. This allows us to hide the entire class from the global namespace and improve or encapsulation even more. If you have comments to the code above, please let me know. I have worked some with Javascript of course, but I am still learning a lot about it.

1 comment:

  1. This article also shows how we can use LocalStorage in HTML 5 through Javascript.

    ReplyDelete