5 JavaScript Techniques Your Should Be Using

Through fire and flames, I’ve learned quite a few JavaScript techniques that have assisted in improving productivity, code quality, and code maintainability. Although simple in nature, I’d like to share the five techniques that I’ve found most beneficial when writing JavaScript:

1. Closures

A closure, in its most basic form, looks like a function within a function. This is a powerful concept because all local variables inside of an inner function can be relatively accessed after that function has returned. I like to think of closures as a particular scope’s “save state”. Free variables contained within closures are remembered, even after that function is returned. Closures are great because they provide scope to your functions and help protect sensitive areas of code.

function outer ( x ) {
    // x is a free variable within inner,
    // but when inner returns, the reference
    // to x’s value is saved and its scope
    // is “closed over”
    function inner () {
        return x;
    }
    return inner;
}
var hello_world = outer( “hello world” );
// when inner closes over, x’s value of
// hello world is closed within that instance
// and returned to the hello_world namespace
console.log( hello_world() ); // hello world

Closures are used all over the place in JavaScript frameworks — probably in many places you’re not even aware of. It’s important to know what a closure is, but even more important to know how to use it. One of the most frequently used closure patterns is the Immediately-Invoked Function Expression. You will often see this expression where protecting scope is imperative.

(function( window, undefined ){
  // variables defined within the instance of
  // this closure are protected from the global
  // scope; however, we can attach them to the
  // sanitized window object for external reference
  var local_var = ‘foobar’;
  window.global_var = local_var;
})( this );
// this example of an IIFE creates a closure
// within it’s own scope, and both invokes and
// returns itself to it’s parent scope
console.log( typeof local_var ) // ‘undefined’
console.log( global_var ); // ‘foobar’
// in this example, the “inner” function is immediately
// closed over on itself when invoked; however, if it
// were named and set to a namespace, ‘local_var’ would
// be relatively accessible via the inner function’s scope

2. Object Literals

An object literal is a custom object defined in your code. Object literals are used in several ways, such as: containing multiple variables without polluting the global namespace, creating API objects, and passing neatly mapped data into a function. Here are examples of object literals in action:

// containing multiple variables
var data = {
  number: 55,
  string: “Hello World!”,
  array: [ “foo”, “bar” ]
};

Wrapping related data in an object literal grants scope to the data, as well as cleaning up the local namespace.

// creating API objects
var API = {
  foo: function ( data ) {
    // methods scoped to the “API” namespace
  }
};

Creating API methods as part of an object literal grants specific scope to each method. This is highly advantageous due to each API’s ability to be quarantined, version-ed, and debugged with ease.

// passing mapped data to functions
function foo ( params ) {
  for ( key in params ) {
    console.log( key, params[key] );
  }
}
API.foo({
  number: 55,
  string: “Hello World!”,
  array: [ “foo”, “bar” ]
}); // number 55 \n string Hello World \n array foo bar

Using object literals to pass data to a method is helpful when there are multiple arguments. Since object literals act as key-value stores, they can be passed in any order, allowing the API’s method to scale without updating each callee instance ( just be sure to validate object existence on required keys ).

3. Namespaced Application Objects

One of the great things about JavaScript is its ability to be written in many ways. However; this can also be a great pitfall if the author does not keep their code structured well. Globally namespacing an application object helps keep all system utilities and methods organized and easy to work with.

( function ( window, undefined ) {
  var APP = {
    init: function () {
      console.log( APP.pets, APP.favorite.color, APP.favorite.number );
    },
    pets: [ “cat”, “dog”, “fish” ],
    favorite: {
      color: “blue”,
      number: 55
    }
  }
  // attaching this object to the global namespace allows attributes to be accessed
  // outside the scope of this closure – some like to emulate the concept of “private” methods
  // by not attaching those parts of the application object to the global scope
  window.APP = APP;
  $( document ).ready( APP.init ); // cat dog fish \n blue \n 55
})( this );

4. Console and Developer Tools

Problems are easily solved when enough data is provided regarding the issue. Browser development tools provide a console object and interface that can process data and browser information which is priceless when fixing JavaScript bugs. Logging data is a crucial tactic used in every programming language, so knowing how to use the console is necessary. I use the developer tools bundled in Google Chrome ( mostly because the V8 JavaScript engine is ridiculously fast ). Reading up on your dev tools’ abilities can drastically increase your productivity.

Chrome Dev Tools

Firefox Dev Tools

5. TDD

Test Driven Development is an essential part of our process at QuickLeft. Most developers have some experience in testing code, but are they actually test driving it? Test driving your JavaScript results in cleaner, more stable code. JavaScript can be hard to write in an organized manner. Frameworks like jQuery and Prototype make it very easy to develop code soup. Every large JavaScript project I’ve seen that isn’t test driven ends up in a big mess of bind events, meaningless closures, and random half-baked functions that don’t work in certain contexts. These inefficiencies often bloat the project budget and bug list significantly. Although the benefits of testing are sometimes argued against, there is no supportive defense that outweighs the amount of structure and stability test driving your JavaScript will enforce.

Not all tests are created equal. It is very important to make sure your tests cover the right functionality. Different project types call for different testing methodologies. In an event-driven application, any function that could be used from more than one context should be abstracted from it’s origin into a helper or API method. Test driving these methods help insure stability from an external context, but more importantly, it helps force the developer to write scalable and well structured code.

If you want to try TDD but don’t know where to get started, I would reccomend playing with Jasmine, QUnit, or PhantomJS:

Jasmine

QUnit

PhantomJS

Advertisements