JS Best Practices

A simple guide to tools and best practices when using JavaScript and jQuery.

Scroll down...

Content

Resources

Comments

Because of JavaScript's asynchronous and function-driven nature, it's easy to go all Wild West with your code and devolve into bad practices. Where does your code go? How do you keep things nicely namespaced? How do you give your code structure that makes it simple to improve and maintain?

These aren't minor questions. Having no idea how to organize your code can be a major roadblock to conceptualizing problem solutions.

In this lesson, we'll talk about some best practices for organizing your JavaScript code, handling basic performance considerations and, of course, reading the documentation.

Reading the Documentation

Before we get into the good stuff, let's take a minute and look at the jQuery documentation. If all goes well, you'll spend plenty of time poking around the documentation so we'll do a quick intro here.

The docs are located at http://api.jquery.com/, and they are pretty to-the-point.

To get started, the documentation is just an ordered list of all the methods attached to the $ (jQuery) object. Each method is tagged and you can filter based on those tags using the menu on the left:

jquery API docs

For a brief intro, we'll look at a slightly meatier function like on() (docs here).

To kick things off, pay attention to the method signature(s). If there are multiple signatures provided, there are multiple ways to call the function (this usually means a different lineup of required arguments). They usually result in the same thing, but might not be appropriate for your use case.

In the method signature, any arguments in brackets are optional.

Pay attention to what data type each method argument expects. In the example here, a major difference between the two ways of calling this on() function is that you can pass either a String or an Object for the events argument. This is often the difference between two listings for the same method which otherwise appears to have the same signature.

JavaScript and jQuery methods frequently give you the option of either passing a simple String or multiple options inside an object like this. With on(), you can see this immediately just by glancing at the doc page "Type" for the events parameter:

jquery API docs on

In this case, you can pass in an object where the "string keys represent one or more space-separated event types". Essentially, run on multiple times with one call instead of spacing it out over multiple calls:

// The boring vanilla way to set up two event handlers
$("p").on("click",function(){ console.log("Clicked!") } );
$("p").on("mouseenter",function(){ console.log("Entered!") } );

// Remove the old handlers
$("p").off();

// Now use the object version that we just discovered
// This is identical to the above.
$("p").on({
  "click":      function(){ console.log("Clicked!") },
  "mouseenter": function(){ console.log("Entered!") }
});

Get used to passing in objects to represent multiple calls to the same function. In this case, just peeking at the docs gives you all the help you need.

The second place to stop when you visit a new method or one you're trying to remember is the examples section. You're probably in a rush to just get the dang thing working but don't skip out on the 5 seconds it takes to read the method signatures above. It will save you much grief.

Once you've done so, the explanation section and examples down below are often good reference material (though they won't cover every case!). Sometimes there are even live demos at the bottom you can play with:

jquery API docs demos

Hopefully, this quick documentation walkthrough will prepare you to spend less time hacking together solutions and more time learning to use the methods you want.

Encapsulating Code in Objects

You know good engineering principles by now -- DRY up your code, modularize different functionality and decompose complicated processes into multiple sub-processes. So why does your JavaScript still look like spaghetti?

Spaghetti code

That's okay, you're still learning. But here we're going to show you how to tighten up your code. A few problems you have are probably related:

  1. You have all your variables and functions declared in the global namespace. This is not sustainable in a production application -- you'll run into all kinds of issues with namespace collisions when other functions want a piece of the action.
  2. You have all your functions declared together even though some are completely unrelated to others. They might all be wrapped under a single $(document).ready(function(){...}) or just left willy-nilly throughout code.

These issues are solved through the use of JavaScript objects and what we'll call the Object Pattern. Objects are everywhere in JavaScript and with good reason. They are containers that you can use to store all your variables and functions. Sounds like a good candidate for organizing code...

Taking advantage of JavaScript's objects is easy. Simply enclose your code in objects. That means declaring your functions and variables as code inside an object that safely encapsulates them away from the global namespace. Then you can access these variables as properties of the object and the functions as methods on the object. It's easy to make multiple different objects to cover multiple different types of functionality.

The jQuery object already does this. Another example of this would be:

// The BAD OLD WAY
// Note that waiting for the document to load
// is a standard practice regardless of what
// pattern you're using.
$(document).ready(function(){
  var var1 = "val1";
  var var2 = "val2";
  var func1 = function(){ ... };
  function func2(){ ... };
});

// Calling the BAD WAY items
// Yuck! Pollution of global namespace!
var1;
func1();
func2();

// The BETTER Way
// Wrap related functions and vars in an object
$(document).ready(function(){
  var myObj = {
    var1: "val1",
    var2: "val2",
    func1: function(){...},
    func2: function(){...}
  }
});

// Call the BETTER WAY items
// All are now namespaced under myObj
// ...sublime...
myObj.var1;
myObj.var2;
myObj.func1();
myObj.func2();

// Set some vars, including a new one
// This is just objects 101
myObj.var1 = "val3";
myObj.varNew = "val4";

This is an incredibly powerful pattern! Even if you still have every variable and function all stuffed into a single object, you've made a vast improvement over keeping them scattered throughout the global namespace.

Objectifying Anonymous jQuery Functions

We want to specifically address a common problem when working with jQuery. The problem is that it's insanely easy to start piling up gobs of anonymous functions that attach handlers to elements on your page or perform AJAX operations (which you'll see soon enough):

$( document ).ready(function() {

  $( "#header" ).click(function( event ) {
      $( "#newsletterModal" ).slideDown(function() { ... } );
  });

  $( "#some-container" ).load( url , function() { ... } );

  ...

});

These may seem more harmless than explicitly setting variables or functions in the global scope (like we looked at above), but it's just as problematic. Do yourself a favor and use the Object Pattern to store these jQuery functions and their previously-anonymous callbacks as named functions inside an object:

var clickHandlers = {

  init: function() {
    // Note that we're again using the objects itself
    // to call functions on and access properties of
    $( "#header" ).click( clickHandlers.dropNewsletterModal );
    $( "#some-container" ).load( clickHandlers.url, clickHandlers.yetAnotherCallback );
  },                                      // Comma! We're in an object...

  dropNewsletterModal: function( event ) {
    $( "#newsletterModal" ).slideDown( anotherCallback );
  },

  anotherCallback: function() { ... },    // Comma! We're in an object...

  yetAnotherCallback: function() { ... }  // Comma! We're in an object...

  url: "http://www.example.com/data",     // Comma! We're in an object...

};

$( document ).ready( function(){ clickHandlers.init() } );

This still accomplishes the same setup as your spaghetti code only with fewer meatballs.

Use CSS Classes

If you're changing the styling of an element, try to avoid the css setter. This sets styles by using inline styling on the element and that leaves your code spread out and brittle. Instead, use addClass and removeClass to add classes onto the element in question. Define the styles for those classes in your stylesheets as normal.

A common example can be if you have a hidden class or an active class which gets programmatically set depending on the user's behavior. It's easier to just add or remove or toggle the classes than it is to manually go around looking for the elements which have the properties you want.

If you want to modify hidden classes, for instance, it's also easier to do a jQuery search for $(.some-wrapper .hidden) than it is to look for all the display: none style attributes out there.

So use classes, not inline styles. You knew that already :)

Use jQuery Method Chaining for Element Creation

When creating elements with jQuery, don't use concatenated strings! It works of course, but many things work that you shouldn't do. Instead, prefer the convenience of jQuery method chaining.

For example:

// bad
var $h1 = $(
  '<h1 id="my-heading" class="bar" data-cool="whoa">' +
    '<a href="#" title="Awesome" data-sweet="dude">Awesome</a>' +
  '</h1>'
);

// good
var $a = $('<a></a>')
  .attr('href', '#')
  .attr('title', 'Awesome')
  .attr('data-sweet', 'dude')
  .text('Awesome');

var $h1 = $('<h1></h1>')
  .attr('id', 'my-heading')
  .addClass('bar')
  .attr('data-cool', 'whoa')
  .html($a);

You will see the benefit of this when you begin creating larger DOM elements with jQuery.

Helper Functions for Large DOM Element Creation

If you're creating a large DOM element, you probably want to encapsulate the jQuery calls that create that element in a function. Then you can simply pass the dynamic bits to the function and save big on keeping your code DRY.

A common use case for this is showing Bootstrap dismissible alert messages after some action or event.

What you don't want to do is hard code a single jQuery call somewhere in a script tag in your HTML file. Instead, you should create a helper function that takes care of the heavy lifting so you can call it in some lightweight JavaScript later.

Here is an example:

// bad
var alertType = 'success';
var alertMessage = 'You did it!';

// Too much hard coding, messy strings and not DRY
var $alert = $(
  '<div class="alert alert-' + alertType + ' alert-dismissible" role="alert">' +
    '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
      '<span aria-hidden="true">&times;</span>' +
    '</button>' +
    alertMessage +
  '</div>'
);

$('#flash').html($alert);


// good

// This function would go in a .js file somewhere
function createAlert(alertType, alertMessage) {
  var $span = $('<span>')
    .attr('aria-hidden', 'true')
    .html('&times;');

  var $button = $('<button>')
    .attr('type', 'button')
    .addClass('close')
    .attr('data-dismiss', 'alert')
    .attr('aria-label', 'Close')
    .html($span);

  var $alert = $('<div>')
    .addClass('alert')
    .addClass('alert-dismissible')
    .addClass('alert-' + alertType)
    .attr('role', 'alert')
    .html($button + alertMessage);

  return $alert;
}

// Then call it when you want an alert
var alertType = 'success';
var alertMessage = 'You did it!';
var $alert = createAlert(alertType, alertMessage);

$('#flash').html($alert);

In short, take advantage of the power of jQuery and utilize good coding patterns to jet fuel that power!

Use Strict Mode

Strict mode is an ECMAScript 5 feature. This means it is available in all the current versions of the most popular browsers. The short definition is that it makes the JavaScript parser throw errors for code that would usually run but be coded with bad practices. A longer description is provided here by Mozilla:

ECMAScript 5's strict mode is a way to opt into a restricted variant of JavaScript. Strict mode isn't just a subset: it intentionally has different semantics from normal code. Browsers not supporting strict mode will run strict mode code with different behavior from browsers that do, so don't rely on strict mode without feature-testing for support for the relevant aspects of strict mode. Strict mode code and non-strict mode code can coexist, so scripts can opt into strict mode incrementally. - MDN

Using strict mode is fairly easy. However, it is important to understand what is really going on when you use it.

Let's say you load this script into your HTML file:

"use strict";

foobar = 'foobar';

function barfoo() {

  fizbaz = 'fizbaz';
}

barfoo();

You'll see an error that says something like ReferenceError: Can't find variable: foobar. Why? It's because "use strict"; is recognizing foobar as a reference to an existing variable. Because there is not any declaration anywhere with var foobar; the parser throws an error because it is an undeclared variable. But why is this useful? Why do we want more errors to be thrown?

The answer is because now we remove the ability to accidentally declare global variables in our scopes. Great! Now add a var keyword to make it var foobar = 'foobar';. Run it again and you'll get the same error for fizbaz. The same reason applies here, we have a variable defined without using var so "use strict"; is throwing a helpful error for us. So now we need to put var before fizbaz as well.

Here is the updated code:

"use strict";

var foobar = 'foobar';


function barfoo() {

  var fizbaz = 'fizbaz';
}

barfoo();

As you can see "use strict"; has some definite advantages. Disallowing accidental global variables is a big help! Later you'll see more about how you can use strict mode to not conflict with other libraries that may not use strict mode. For now, use it in your projects atop your JavaScript files to get the parser keeping a close eye on those mistakes for you.

Developing Tips

  1. Test your JS code in JSLint.com by pasting it in or use an in-editor linter.
  2. Use JSHint, a more practical derivative of JSLint, to provide real-time feedback for errors in your JavaScript code. JSHint plugins for your text editor are available elsewhere on the web.

For a complete setup, check out this Atom editor setup.



Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

Sorry, comments aren't active just yet!

Next Lesson: Test Yourself: Dynamic jQuery