enhancing your javascript getting a little more structure in your tools

Enhancing Your JavaScript – Getting a Little More Structure in Your Tools

If you’re new to JavaScript or have a background in programing with languages that are a bit more rigid, writing JavaScript can feel a bit like the wild west. Compared to many other languages it can be really flexible. Everyone who’s worked on websites long enough has come across that bit of code that resembles duct tape holding things together. It kind of makes sense, while you also wonder how it got there; sometimes realizing it was yours after reviewing the commit history 😧

Let’s be fair, duct tape code appears in every language, but in my experience it’s extra-prevalent in JavaScript and that’s likely due to the lack of structure natively provided by the language itself. All that flexibility is nice, but it doesn’t mean we have to forgo organization.

With this post I will share my journey towards manageable JavaScript enlightenment. I like to call this a quest for the holy grail of JavaScript structure! It’s not as grand as all that however, it’s more like the quest for putting my JavaScript into a pretty box that I can find and debug easily - without frustrating my coworkers. As someone said:

 “Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. Code for readability.”

– Not sure where this started, neither is SO, but it motivates me whenever I feel like writing duct tape.

Well in my opinion, the best way to learn code is to write code. I’ve put together some examples to outline how I was first introduced to structured JavaScript, and the direction my journey has trended. Each example will be shown within the post, but they’re also in CodePen. You are welcome and encouraged, to tinker along while reading. I’ve left out fancy frameworks and third-party tools in these examples because we’re reviewing JavaScript, not *insert an overwhelming number of libraries here* with the exception of jQuery. Now if that makes you want to rage quit reading this post I promise I’ll redeem myself. If that doesn’t make you want to rage quit, you may be in for a surprise. Onward!

EXAMPLE 0 – Objects Give Me Structure!

CodePen: https://codepen.io/abenbot/pen/xjgjMr

We’re starting from 0 because hey, computer science1. So, I’ve written a simple tool which updates the inner content of HTML elements when they contain a `js-message` class. For the purpose of this post what the tool does is less important than how it’s organized. The HTML consists of two div elements, each with the `js-message` class, and a button to call our tool.

Bit of HTML code, this doesn’t change much between the examples:

<div class="js-message">Hello World!</div>
<div class="js-message">What a wonderful day to code</div>
<input type="button" value="Update Messages" onClick="helper.messageUpdater.updateMessages()" />

 

In this first example our tool is called `messageUpdater` and I’ve placed it within a `helper` namespace. If that throws you off, namespaces are explained in [#quick-details-about-JavaScript-namespaces]. `messageUpdater` is simply an object. This was phase 1 of my structured JavaScript journey, keeping variables and functions within an object so they’re logically contained together instead of living globally. Everything may still be referenced globally, but from the `messageUpdater` object.

Quick details about JavaScript namespaces

If you haven’t seen `var namespaceName = namespaceName || {};` before, this is simply a global variable that’s set to itself, unless it doesn’t exist yet, in which case it’s set to an empty object. This works because if `helper` doesn’t exist it will cause a reference error and fail the truth comparison, resulting in setting `helper` to an empty object, the part of the comparison that results in truthfulness. If `helper` does exist, then it passes the truth comparison and it’s set to itself, which means the second half of the OR will be ignored. This allows you to use a global variable among multiple files without overwriting properties on the namespace. A namespace in JavaScript is just a global object for referencing other objects / tools. Being an article on structuring JavaScript, it felt wrong to exclude namespaces.

The MessageUpdater with everything referenced with an object. 

// Using the helper namespace for this tool.
var helper = helper || {};

/**
 * messageUpdater tool for updating DOM messages.
 **/
helper.messageUpdater = {

  /** Settings which may be changed at any time. */
  settings: {
    selector: '.js-message',
    message: 'All your base are belong to us.'
  },

  /** Update DOM messages */
  updateMessages: function () {
    var elems = $(this.settings.selector);

    console.log('Found', elems.length, 'DOM elements to update');

    for (var i = 0; i < elems.length; i++) {
      elems[i].textContent = this.settings.message;
    }
  }

};

window.helper = helper;

 

Here we have an object called `settings` and a function. Nothing fancy, but at least it’s all together behind the `helpers` namespace and the `messageHelper` object reference2. The `settings` object has two properties: `selector` and `message`. Selector stores a selection string for finding HTML elements to update, and message is the message used when those elements are updated. So, settings is used to configure our tool, and the `updateMessages` function does the work of updating messages in the DOM.

We start by collecting all of the elements using a jQuery selector and our `settings.selector` string; remember when I spoke of redemption? We’re not there yet, but bear with me. Then we output to the console the number of elements collected. Finally we iterate over the collection of elements and change their textContent3 properties to our `settings.message`. Click the Update Messages button in the Codepen example to see this in action.

It’s all still publicly accessible, but only through the exposed references. To show this, if you have the CodePen example up, open the CodePen Console and type `helper.messageUpdater.settings.message = ”another message”;` before clicking the `Update Messages` button; if you’ve already clicked the button just refresh the page before changing the message setting in the CodePen console and compare the results. That line of code first references the namespace, then our messageUpdater object, then the settings property of our tool, and finally the message string primitive property that we use when calling the updateMessages function. Don’t feel like clicking the button? I mean hey, if you’re already in the console, why touch the mouse? `helper.messageUpdater.updateMessages()` will do the same as clicking the button. Notice if you leave off the parentheses on the function, what happens?

This keeps the working parts of our tool together nicely but having everything in a JavaScript Object as properties seems a little strange and restrictive. Introducing our next example, the Module Pattern!

1 Don’t worry, references will start at 1

2 If the JavaScript Object looks strange, spend some time here; specifically, the Object Initializer section

3 Expecting innerHTML? MDN’d! Search for “Differences from innerHTML”

Example 1 – Module Pattern! 

CodePen: https://codepen.io/abenbot/pen/RyKYoj

For this next example I left the HTML practically the same, so we’ll skip that part. In the previous example we set helper.messageUpdater to an object. Here we’re setting it to a funky, brackety, function thing. What? Welcome to the Module Pattern! `helper.messageUpdater` is  actually set to the result of an anonymous function that we force to run as a function expression with a closure1. So what’s really going on here? Wrapping an anonymous function `function($) { … }` within a closure like `( … )(jQuery)` forces the anonymous function to execute. So instead of `messageUpdater` being set to a reference of the anonymous function, it’s set to the result of the anonymous function.  Check it out in CodePen, set `helper.messageUpdater = function($){ … }` then if you type `helper.messageUpdater` in the console you’ll get the details of the function because it’s a function reference. Without the closure you would have to type `helper.messageUpdater(jQuery)` to get the results of the function. I’ll come back around to why this is cool.

<div class="js-message">Hello World!</div>
<div class="js-message">What a wonderful day to code, with the module pattern</div>
<input type="button" value="Update Messages" onClick="helper.messageUpdater.updateMessages()" />

 

So we’re writing our tool inside an anonymous function now instead of adding everything within an object. As such, the parts that make up our tool now get referenced as variables instead of object properties. You can leave `var` off, but that doesn’t mean you should2. The piles of commas are gone and we’re returning something! That something looks oddly like an object with the properties of our first example. In fact, if you run `helper.messageUpdater`, without the parentheses, in both the first and second examples, they should look identical. So why the closures and trip to bracket-town?  Here comes the cool part. 

MessageUpdater within the Module Pattern.

// Using the helper namespace for this tool.
var helper = helper || {};

/**
 * messageUpdater tool for updating DOM messages.
 * @param {Object} $ - Selector to use within messageUpdater.
 **/
helper.messageUpdater = (function ($) {

  /** Settings which may be changed at any time. */
  var _settings = {
    selector: '.js-message',
    message: 'All your base are belong to us.'
  };

  var _cantTouchThis = '🦀';

  /** Update DOM messages */
  var _updateMessages = function () {
    var elems = $(_settings.selector);

    console.log('Found', elems.length, 'DOM elements to update');

    for (var i = 0; i < elems.length; i++) {
      elems[i].textContent = _settings.message;
    }
  };

  /** 
   * Returns an object with 'settings' and 'updateMessages' properties.
   */
  return {
    settings: _settings,
    updateMessages: _updateMessages
  }

})(jQuery); // Pass jQuery into the anonymous function.

window.helper = helper;

 

Privateness! Well, JavaScript doesn’t really support privacy, but we can make our code less exposed with the Module Pattern. You may have noticed I haven’t explained the underscores or the crab yet. Underscores on variables within the Module Pattern may be used to convey that a variable is private3. I like writing my code this way, so I have, but I reserve the right to change my mind. Now the crab, you may have also noticed that `_settings` and `_updateMessages` made their way into the properties of our returned object under `settings` and `updateMessages` but _cantTouchThis didn’t. This was on purpose and may have also been an attempt to bridge generational gaps, #HammerTime. So if you compared Example1 and Example2 running `helper.messageUpdater` and poked around the returned object in the console, they should match, and neither have `_cantTouchThis`. This is because there isn’t a public reference to it. `_cantTouchThis` is a variable within the anonymous function and our returned object only references `_settings` and `_updateMessages` through its `settings` and `updateMessages` properties. This is the magic of the Module Pattern, it hides the parts of our tool that would clutter its public interface. When calling `helper.messageUpdater` we don’t need to see `_cantTouchThis`, so it isn’t returned, and instead it’s hidden.

Now if you thought you were going to hide those private, third party API keys in your JavaScript, STOP RIGHT THERE. JavaScript in the browser runs on the client’s machine. Not only do we not have true privateness in JavaScript, your code is also running in someone’s browser each time they view your website. If you put your API Keys in your client-facing JavaScript, assume you’re sharing them with the world. There may be situations where this is okay, just be aware and don’t think of this as a security workaround. Like most private keys, keep them secret, keep them safe.

1 Going into function expressions VS function declarations and closures is beyond the scope of this article. Maybe I’ll dig deeper in another post? Message in the comments if that’s something you’d like to see. Or there’s MDN...

2 SO answer for leaving var off 

3 Another school of thought believes it’s a misleading convention because these variables are not actually private.

Example 2 – Reveal Pattern 👻

CodePen: https://codepen.io/abenbot/pen/MGJzpB

The HTML in this example practically matches the others, so we’ll skip the review. It is a post on JavaScript after all.

<div class="js-message">Hello World!</div>
<div class="js-message">What a wonderful day to code, with the reveal pattern</div>
<input type="button" value="Update Messages" onClick="helper.messageUpdater.updateMessages()" />

 

This final example looks like it’s changed a lot. We have almost double the lines of code here, but if you focus on `helper.messageUpdater` it’s very similar to the previous example. I won’t go through the newly added `helper.logger` much, but I wanted to add it for a few reasons: to show the namespace being more than just another thing to type, provide an example of tools functioning together, and to share something cool you may find inspirational or useful along your code journey. 

Reveal Pattern at work with MessageUpdater and the additional Logger tool. 

// Using the helper namespace for this tool.
var helper = helper || {};

helper.logger = (function () {
  /**
   * Outputs parameter to console when DebugMode is on. Requires binding to an object
   * with DebugMode and Name properties.
   *
   * @arguments {Array} Array of items to print to the console.
   */
  function _debugLogBase() {
    let debugMode = this.debugMode;
    if (typeof debugMode === "undefined") {
      debugMode = true;
    }

    if (debugMode && window.console) {
      // Convert args to a normal array
      var args = Array.prototype.slice.call(arguments);
      if (this.name) {
        args.unshift(this.name + ' -');
      }
      // Pass along arguments to console.log
      console.log.apply(console, args);
    }
  }

  return {
    debugLog: function (settings) {
      return _debugLogBase.bind(settings);
    },
  }
})();

/**
 * messageUpdater tool for updating DOM messages.
 * @param {Object} $ - Selector to use within messageUpdater.
 * @param {Object} logger - Logging tool for logging debug messages.
 **/
helper.messageUpdater = (function ($, logger) {

  /** Settings which may be changed at any time. */
  _settings = {
    name: 'Helper Extension',
    debugMode: true,
    selector: '.js-message',
    message: 'All your base are belong to us.'
  };

  _debugLog = logger.debugLog(_settings);

  /** Update DOM messages */
  _updateMessages = function () {
    var elems = $(_settings.selector);

    _debugLog('Found', elems.length, 'DOM elements to update');

    for (var i = 0; i < elems.length; i++) {
      elems[i].textContent = _settings.message;
    }
  };

  /** 
   * Returns an object with 'settings' and 'updateMessages' properties.
   * This is much like the 'Exposed' example, except the internal parts of 
   * the anonymous function that messageUpdater references are unaccessible.
   */
  return {
    settings: _settings,
    updateMessages: (function () {
      return _updateMessages();
    })
  }

})(document.querySelectorAll.bind(document), helper.logger); // Use a different selector than jQuery

 

Short version of `helper.logger`. `helper.logger.debugLog` is a function that expects an object parameter with `name` and `debugMode` properties. This function returns a function that, when these properties are present, provides additional functionality for debug logging. This is a useful function factory which provides improved debug logging across your tools with re-usable code that exists in a single location. Who doesn’t like DRY code1? All your tools can use the helper.logger.debugLog tool for enhanced logging. Pass in an object with `debugMode` and name properties, if `debugMode` is `true`, all of your debugLog calls will show, if it’s `false`, then they won’t. If name is set, then the name of the tool will be automagically included in your debug output. This may seem trivial, until you’re debugging a site that has JavaScript console logging all over and it isn’t clear what’s firing from where. Click the button in the CodePen example and you’ll see what I’m talking about in the CodePen Console; disclaimer: it looks a little silly with a bunch of quotes when this was written, but your browser console should display the message better without all of the extra quotes.

Like I asked you to change the `helper.messageUpdater.settings.message` before in the console, try it again with the `helper.messageUpdater.settings.debugMode` and `name`, see what happens! Maybe I’ll write a post on binding and the call / apply function methods to dig into some of this further. Leave comments if you’d be interested in something like that. Back to the `helper.messageUpdater`!

The `helper.messageUpdater` tool in this example has been modified to use a local reference of `helper.logger` `debugLog`, instead of `console.log`. Using this other logger benefits from additional properties in the _`settings` object, but the main thing I would like to highlight is what’s changed in our return object. Towards the end of the first example I asked you to type `helper.messageUpdater.updateMessages`, without parentheses, and if you did you would have received the contents of the `updateMessages` function. Then, with the second example you could do the same thing. At least you could hide some of the implementation from the public interface, but whatever was returned was completely visible like before. In this example, if you were to call `helper.messageUpdater.updateMessages` you’ll still see the contents of the reference, but it won’t be the internal `_updateMessages` function. This is because the reveal pattern has the additional feature of wrapping functions inside of, you guessed it, closures. Returning a closure with an anonymous function referencing the internal function obfuscates what’s really going on. And yes, it still accepts parameters, just like how we’re passing references to the `helper.messageUpdater` through its closure.

I’ve been a huge fan of the reveal pattern for my native JavaScript because I have access to everything publicly if I need to debug a tool, but I can also hide what I don’t need to see publicly and obfuscate what I don’t want easily readable. Remember, like I stated in the previous example, the JavaScript is loaded to the client so whoever is viewing your webpage gets all of your JavaScript. The reveal pattern may make your minified or uglified JavaScript harder to read, but it can still be unscrambled.

Time to keep my promise and redeem myself, but first, some background. jQuery filled a void in JavaScript around 2012 but as web technologies have progressed some people now regard it as an unnecessary, large library. A huge appeal to jQuery was its’ selector. It’s easy to type and can select HTML elements from the DOM simply with a pattern; like `$(“.js-message”);` instead of `document.getElementbyClassName(“js-message”);`. jQuery’s selector syntax was a godsend. Well, we’ve had `document.querySelectorAll`2 natively in JavaScript for a long while now and it can do most of what jQuery’s selector can; it even has basic support in IE8.

But wait, did I just move away from my easy `$(“pattern-here”)` syntax? There’s a fix for that. Feel free to set these globally in projects that aren’t actively using jQuery, `var $ = document.querySelector.bind(document); var $$ = document.querySelectorAll.bind(document);` and BAM, that jQuery feel from native JavaScript and no libraries loaded to achieve it. Some browsers actually do this by default in their console when jQuery hasn’t been loaded, and we’ve done it in our final example - Stop, Redemption Time!

But wait, the selector code didn’t change? Right. Where we were passing jQuery to the anonymous function through the closure we are now passing `document.querySelectorAll.bind(document)`. The anonymous function uses the selector internally with the `$` parameter. Neat right? This isn’t a direct replacement for jQuery, so don’t go running off replacing everything and expecting it all to work, but a promise is a promise. I wanted to show why it’s a good idea to pass external references into your tools instead of directly referencing them everywhere; it’s easier to refactor or upgrade your code when the tools working together are loosely coupled.

1 Don’t Repeat Yourself

2 I can’t really recommend MDN enough

The End

So we started with putting all of our JavaScript into an object then moved onto the Module Pattern. There we wrapped our code in an anonymous function, within a closure, then tweaked the Module Pattern with the Reveal Pattern and obfuscated our publicly referenced functions. The rabbit hole goes deeper still however. We haven’t touched on init or terminate functions, the lifecycle of your tools, or how to design them to be more performant. Perhaps in another blog post.

Leave a comment to give me an idea what you liked (or didn’t like) about this post and if you’d like another post on something similar. And to be honest this is my first post, so I’m grateful for all of the feedback I can get, positive or constructively negative. Thanks for sticking around and reading through it all. Even though this became much larger, and took much longer to write, than expected, it’s been a good experience on this end.

Ben Cawrse

Ben approached software with a traditional education and achieved master’s and bachelor’s degrees in Computer Science as well as minors in Computer Engineering and Modeling and Simulation. While in college he worked on campus in a software lab performing research and directly interning with the lab’s clients, gaining heavy exposure across a diverse set of technologies. Since joining Marathon, Ben has primarily been focused within the digital marketing group building and supporting websites on the .Net framework. Away from the computer, Ben enjoys hiking, rock climbing, and exploring various hobbies to stay active.

Leave a Comment

Let's talk about your project.

We are full-service, flexible, and believe that successful projects are the result of working collaboratively with our clients. Are you looking for a better user experience for your website or application? Need an experienced database architect or business analyst? Let’s talk!

X