Tags

,

JavaScript, a language of love, hate, and hard knocks. I actually love JavaScript, it is a great language to work with and extremely flexible but that flexibility can cause enormous headache and for that reason there are many who won’t even look at js.

JavaScript is one of those languages where you can spend years using it and never even scratch the surface of its potential. Now I believe that you can never know 100% about a subject but I do feel fairly confident with my JS, I figure that by now I must have at least 10% in the bag, so here are a few small tips I’ve picked up on the way.

#1 Magic Object Selection

Take advantage of logical operators

Okay it’s not really magic, but it’s still pretty cool. You can take advantage of the way javascript treats logical operators in order to fallback to other objects/functionality. Consider the following code snippet:


function setBackground(tcColour, toElement)
{
  (toElement || document.body).style.background=tcColour;
}

setBackground('green', document.getElementById('myElement'));  // sets myElements' background to green
setBackground('red'); // sets the body background to red

If the toElement parameter is not supplied it will be defaulted to document.body. Pretty neat and extremely useful.

#2 Watch those loop counters.

Build habits not skills

This one is a good habit to get into and I’ll explain why after the code snippet:

Instead of this:


var laArray = [1,2,3,4,5,6];
for(var i=0; i<laArray.length; i++)
{
	doSomethingWith(laArray[i]);
}

Write this:


var laArray = [1,2,3,4,5,6];
for(var i=0, lnLength=laArray.length; i<lnLength; i++)
{
	doSomethingWith(laArray[i]);
}

Why? Well the for loop is structured as three statements, the initialisation (var i=0), the condition (i<lnArray.length), and the increment (i++). Of these parts the initialisation gets executed once and both the condition and increment get executed each time the loop iterates. While generally this isn't too much of a problem because the time lost is negligible, think about this if your conditional was i<myObject.timeConsumingFunction(); The loop would become seriously slow. By adjusting to the second form, the actual condition will only be executed one time and a simple comparison will be executed on each iteration. Nobody likes taking the hits, so only take it once if you can.

#3 You can change the language.

Don’t accept the status quo

Yes, that’s right, you don’t have to accept things as they come. Say you wanted a quick function on strings that removed the whitespace from both sites of the string. And lets just call the function allTrim as there is a similar function in T-SQL that does the same.


String.prototype.allTrim = function()
{
    return this.replace(/^\s+|\s+$/g, '');
}

console.error("        THIS IS MY STRING      ".allTrim());

Output: “THIS IS MY STRING”;
Now that is the stuff dreams are made of!

#4 You can pass functions around as if they are objects

Comparing apples and oranges is easy

Functions in javascript are first class objects. What does that mean, well it’s simple, that means functions can be treated like any other object, functions have properties, can be stored in variables, and can be passed around at run time.

Why would this ever be useful? Well that’s what we are talking about now. Callbacks are functions that are executed once something has happened or during specific times during the execution of another function, for example say you wanted to receive an array of numbers and add one to every number, without a callback you may write something along the lines of:


function increment(taIntegers)
{
	for (var i=0, lnLength=taIntegers.length; i<lnLength; i++)
	{
		taIntegers[i]=taIntegers[i]+1;
	}
	return taIntegers;
}
var loIntegers = [1,2,3,4,5,6];
console.error(increment(loIntegers));

Output: [2,3,4,5,6,7]
Everything works, the world is great. Then specs change and in some cases you need to decrement rather than increment and also you know that there is another change coming where you will have to multiply by 15, it just never ends.

There may be a temptation to write a decrement function, a multiply function and all the other functions using a copy paste methodology and the world will still rotate on its wobbly axis, however your job could have been much easier if you make use of the first class function object principle.

Taking in some of the design principles from that great gang of four we could create a template for what we are trying to do, then each manipulation or strategy could be coded (and therefore nicely unit tested) separately as follows:


function map(taArray, toCallback)
{
  for (var i=0, lnLength=taArray.length; i<lnLength; i++)
  {
    taArray[i] = toCallback(taArray[i]);
  }
  return taArray;
}

function increment(tnValue)
{
  return tnValue+1;
}

function decrement(tnValue)
{
  return tnValue-1;
}

console.error(map([1,2,3,4,5,6], decrement));

console.error(map([1.1,2.2,3.3,4.4,5.5,6.6], increment));

Output:
> [0, 1, 2, 3, 4, 5]
> [2.1, 3.2, 4.3, 5.4, 6.5, 7.6]

Now while this example is very simple, I’m sure that the power behind it can be seen without much difficulty (if not, don’t panic, just ask questions in the comments section, I love the feedback and it does my klout score wonders).

Defining a function based on browser capabilities

Self organising code? Well self modifying anyway.

Whuuut? Defining a function based on what features are available in the browser. Now why… oh yeah, IE.

I’ve seen a lot of code written as follows for doing “feature detection”:


var g_oUtilityObject = {
  addEventListener : function(toCallback, tcEventType, toElement)
  {
    // Default to the document if no element was provided
    toElement = toElement || document;
    if (toElement.addEventListener)
    {
      toElement.addEventListener(tcEventType, toCallback, true);
    }
    else
    {
      toElement.attachEvent("on" + tcEventType, toCallback);
    }
  }
};

So now you have a nice simple cross browser version of addEventListener that you can use where you like without any worry. The only issue with this method is that the if statement is executed every time addEventListener is called. After the first time we already know which path we want to go down, so why not let the code “rewrite” itself based on that condition. Give this a go:


var g_oUtilityObject = {
  addEventListener : (function(){
    return document.addEventListener ?
      function(toCallback, tcEventType, toElement)
      {
        (toElement||document).addEventListener(tcEventType, toCallback, true);
      } :
      function(toCallback, tcEventType, toElement)
      {
        (toElement||document).attachEvent("on" + tcEventType, toCallback);
      };
  }())
};

Now we have a function which when created makes the decision as to its actual definition, and only at the point of creation is the decision made, and most importantly only one time. Again nobody likes to take the lumps but somebody has to, so take them once.

Notice the ternary in there, I also love the ternary. Thats the sixth secret hint for those that read this far. Gotta love the ternaries. Did I mention the ternaries?

And that’s it for now there is much more to javascript but these are just a few quick tips that I find I’m sharing quite a lot.

Advertisements