Saturday, 26 September 2009

Using Lazy Function Definition

Redefining functions in a good way

Javascript is a language that lets you overwrite existing objects and functions very easily. This can be a curse when it happens without you realising which is why namespaces are always a good idea when you are developing a site that makes use of numerous scripts, frameworks and add-ons. I even blogged the other day about some trouble I had when a helper function was overwritten by another library which caused some issues: http://blog.strictly-software.com/2009/09/trouble-with-this-keyword-and.html

However one of the ways that overwriting functions can be good for your coding is when the function contains a computation or test that only needs to be run the first time the function is called. You can run this test and then overwrite the function to return the value depending on the computation.


A Debugger example

A lot of times when I am quickly testing some code without including extra scripts I want to be able to output debug messages to help with the testing. I usually want to output to the console if available but some browsers don't allow the console to be locked to the window or with IE and sometimes FireFox / Firebug I may not want to use their console due to issues with speed and locking. In these cases I just create a DIV at the bottom of the screen to output messages to with some HTML like this:
<div style="width:98%;overflow:auto;background:white;height:200px;color:black;text-align:left;border:1px solid black;" id="output"></div>

I then use a function called ShowDebug to output the messages. Now I have seen similar code on the web and have written some myself that would use the following logic within the ShowDebug function to decide whether to output to the console or the DIV.
var logToDiv = false;
var c = 1;
ShowDebug = function(m){
if (typeof(window.console)=="undefined" || logToDiv){
var msg = c + ": " + m + "<br />";
G('output').innerHTML=G('output').innerHTML+msg;
c++;
}else{
console.log(m)
}
}

However as you can see this would be quite expensive as for every call to ShowDebug the same conditional test is being carried out. If you are making thousands of calls to this function then this is quite an overhead and one that can be removed.


The better way - Lazy Function Definition

The better way is to run the conditional test for the console or DIV on the first call to ShowDebug and then overwrite the ShowDebug function to use the appropriate method from then on. All subsequent calls will either just output to the console or to the DIV.
ShowDebug = function(m){
var logToDiv = false;
if (typeof(window.console)=="undefined" || logToDiv){
var c = 1;
ShowDebug = function(m){
var msg = c + ": " + m + "<br />";
G('output').innerHTML=G('output').innerHTML+msg;
c++;
}
}else{
ShowDebug = function(m){
console.log(m)
}
}
ShowDebug(m);
}

This is called Lazy Function Definition and although this is a very basic example it shows you the possibilities of its use to avoid expensive mathematical computations or checks for non-existing properties or values on each function call.

Here are some articles that go into this concept in more depth:




No comments: