JavaScript Best Practices - Code Like a Pro (Pt. 1)

Beginners Series Episode 2 😁🥂

JavaScript Best Practices - Code Like a Pro (Pt. 1)

Hey! Have you seen our Beginners Series Episode 1? You can check it out Here. Thank you!

Welcome to the second episode of our Beginners Series. In this episode, we will look at the best practices to follow while writing your JavaScript codes.

You want to write your codes like a pro? Account for less bugs, maximum security and speed optimization?? You want to own your code and be proud to share with other devs??? Jump on this awesome read as I buttress some practices to imbibe while writing JavaScript.

1. Avoid Globals Declarations

Global variables and function names are an incredibly bad idea. The reason is that every JavaScript file included in the page runs in the same scope. If you have global variables or functions in your code, scripts included after yours that contain the same variable and function names will overwrite your variables or functions.

There are several workarounds to avoid using globals — we’ll go through them one by one now. Say you have three functions and a variable like this:

var current = null;
function init(){...}
function change(){...}
function verify(){...}

You can protect those from being overwritten by using an object literal:

var myNameSpace = {
  current:null,
  init:function(){...},
  change:function(){...},
  verify:function(){...}
}

Global declaration is avoided but there is a drawback — to call the functions or change the variable value you’ll always need to go via the name of the main object: initializing is myNameSpace.init(), current is myNameSpace.current and so on. This can get annoying and repetitive.

We can use Module Pattern to wrap the whole thing in an anonymous function and protect the scope. That also means you don’t have to switch syntax from function name() to name:function().

myNameSpace = function(){
  var current = null;
  function init(){...}
  function change(){...}
  function verify(){...}
}();

Again, this approach has its shortcomings. None of these are available or can be accessed from outside anymore. To make any or all of them available, we use return statement to make public them available. Also to eliminate changing syntax, we return pointers to the function instead of the properties and method

NOT THIS

myNameSpace = function(){
  var current = null;
  function verify(){...}
  return{
    init:function(){...}
    change:function(){...}
  }
}();

BUT THIS

myNameSpace = function(){
  var current = null;
  function init(){...}
  function change(){...}
  function verify(){...}
  return{
    init:init,
    change:change
  }
}();

This makes it easy to call functions and access variables from other places without having to go through the myNameSpace name.

It also means that you can have a public alias for a function in case you want to give it a longer, descriptive name for internal linking but a shorter one for the outside:

myNameSpace = function(){
  var current = null;
  function init(){...}
  function change(){...}
  function verify(){...}
  return{
    init:init,
    set:change
  }
}();

Calling myNameSpace.set() will now invoke the change() method.

If you don’t need any of your variables or functions to be available to the outside, simply wrap the whole construct in another set of parentheses to execute it without assigning any name to it:

(function(){
  var current = null;
  function init(){...}
  function change(){...}
  function verify(){...}
})();

This keeps everything in a tidy little package that is inaccessible to the outside world, but very easy to share variables and functions inside of.

2. Optimize Loops

Loops can become very slow or break stuffs in your code if you don’t write them the right way.

One of the most common mistake is to read the length attribute of an array at every iteration, for example:

var names = ['George','Ringo','Paul','John'];
for(var i=0;i<names.length;i++){
  doSomeThingWith(names[i]);
}

This means that every time the loop runs, JavaScript needs to read the length of the array — This can slow things down. You can avoid that by storing the length value in a different variable:

var names = ['George','Ringo','Paul','John'];
var all = names.length;
for(var i=0;i<all;i++){
  doSomeThingWith(names[i]);
}

An even shorter way of achieving this is to create a second variable in the pre-loop statement:

var names = ['George','Ringo','Paul','John'];
for(var i=0,j=names.length;i<j;i++){
  doSomeThingWith(names[i]);
}

Another thing to ensure is that you keep computation-heavy code outside loops. This includes regular expressions and more importantly, DOM manipulation. You can create the DOM nodes in the loop but avoid inserting them into the document. You’ll find more on DOM best practices Here.

3. Modularize — One Function Per Task

This is a general programming best practice — making sure that you create functions that fulfill one job at a time makes it easy for other developers to read, debug and change your code without having to go through the difficulties of finding what block of code performs what function.

This also applies to creating helper functions for common tasks. If you find yourself doing the same thing in several different functions then it is a good idea to create a more generic helper function instead, and reuse that functionality where it is needed.

Say you wanted to write a helper function to create new links. You could do it like this:

function addLink(text,url,parentElement){
  var newLink = document.createElement('a');
  newLink.setAttribute('href',url);
  newLink.appendChild(document.createTextNode(text));
  parentElement.appendChild(newLink);
}

This works ok, but you might find yourself having to add different attributes depending on which elements you apply the link to. For example:

function addLink(text,url,parentElement){
  var newLink = document.createElement('a');
  newLink.setAttribute('href',url);
  newLink.appendChild(document.createTextNode(text));
  if(parentElement.id === 'menu'){
    newLink.className = 'menu-item';
  }
  if(url.indexOf('mailto:')!==-1){
    newLink.className = 'mail';
  }
  parentElement.appendChild(newLink);
}

This makes the function more specific and harder to apply to different situations. A cleaner way is to return the link and cover the extra cases in the main functions that need them. This turns addLink() into the more generic createLink():

function createLink(text,url){
  var newLink = document.createElement('a');
  newLink.setAttribute('href',url);
  newLink.appendChild(document.createTextNode(text));
  return newLink;
}

function createMenu(){
  var menu = document.getElementById('menu');
  var items = [
    {t:'Home',u:'index.html'},
    {t:'Sales',u:'sales.html'},
    {t:'Contact',u:'contact.html'}
  ];
  for(var i=0;i<items.length;i++){
    var item = createLink(items.t,items.u);
    item.className = 'menu-item';
    menu.appendChild(item);
  }
}

By having all your functions only perform one task, you can have a main init() function for your application that contains all the application structure. That way you can easily change the application and remove functionality without having to scan the rest of the document for dependencies.

4. Stick to a Strict Coding Style

Browsers are very forgiving when it comes to JavaScript syntax. This should not however be a reason for you to write sloppy code that relies on browsers to make it work.

The easiest way to check the syntactical quality of your code is to run it through some basic tools that check for errors and optimizations. One of the basic tools is JSLint — a JavaScript validation tool that gives you a detailed report about the syntax warnings and their meaning.

JSLint can be a bit touchy about the results it returns and — as its developer Douglas Crockford says — it can hurt your feelings.

You will find yourself writing better code when subjecting your code to JSLint or any other linting tools scrutiny.

Clean and valid code means less confusing bugs to fix, easier handover to other developers and better code security. When you rely on hacks to get your code to work it is likely that there is also a security exploit that uses the same hacks. In addition, as hacks get fixed in browsers, your code will cease to work in the next version of the browser.

Valid code also means that it can be converted by scripts to other formats and need less or no human refactoring which is prone to error and consumes time.

Conclusion

Hello devs, let's have a little break on this episode, we will return next week with the Part 2 of JavaScript Best Practices. While we chill and wait, it will be awesome to try these new practices in your recent projects. Feel free to tell me what you think in the comment section too.

Some articles referenced here for more clarity are:

Code Like a Pro till the next episode 🥂😁.