Friday, April 20, 2012

console.log for all browsers...

Just a line of JavaScript that allows me lo leave my 'console.log' lines while doing cross-browser development:

var console = console || { log: function() {} };

'console' is supported in Chrome and IE9 (and some others...) but not in IE6 that chokes on it. The line above just executes a 'null' console.log when console is not supported and lets me keep all the 'console.log' lines while I am developing my code.

Sunday, January 08, 2012

Caching jQuery objects in callbacks

In my code I try to avoid re-computing things when they don't need to be. One thing that John Resig mentions in his blog is that we should avoid re-computing jQuery objects with selector over and over for performance reasons. He talks about Twitter's experience.

I was browsing through John Resig's blog when I saw his "Learning Advanced Javascript" interactive slides here: http://ejohn.org/apps/learn/ . #21 caught my eye, since I have been trying to improve my code when I write callbacks in jQuery:

function isPrime( num ) { 
  ...
  isPrime.cache[ num ] = prime 
  ...
  }

The important part here is that functions can have properties. The issue is that we often need to access DOM elements or jQuery objects from inside the callback function, but we really should not re-calculate, i.e $('.someelements')), the jQuery objects every time the event callback is called. I also want to write the code as a one-liner if I can. I used to write:

var inp = $('#input');
var out = $('#output');

$('#copyname').click( function(e) { out.val(inp.val()); } )

but then the variables would pollute the namespace and make the code more verbose. Until recently I was using the jQuery 'data' property to *cache* the $() call:

$('#copyname').click( {src: $('#inputname')}, function(e) { $('#outputname').val(e.data.src.val()); } );

$('#inputname') is computed only once, but $('#outputname') is still computed every time the callback is called. Also the 'e.data.src' construct assumes a knowledge of jQuery. Granted, I could use an object  in 'src' with both jQuery objects. But instead, let's use a closure:


$('#copyname1').click(
    (function x() { var i = $('#inputname1'); var o = $('#outputname1'); return function(e) { o.val(i.val()); }; })() );

It's easy to read and short, doesn't pollute the namespace. We can also use John's caching technique like this:


$('#copyname').click(
    (function x() { x.i = $('#inputname'); x.o = $('#outputname'); return function(e) { x.o.val(x.i.val()); }; })() );

Here function x is called before the jQuery click function is called. it returns the anonymous callback 'function(e)'. That callback function will be passed the 'e' event object when called by jQuery when the use clicks on the button. The cool thing is that the callback function has access to 'x.i' and 'x.o', created in a closure inside the function x. No need for jQuery repeated calls or data property. The namespace is free of x or any temporary variable.

I just hope that the function x is garbage collected when the click handler is unbound... Any idea how to check that? Is it a good application of closures and function properties?