August 19, 2008

Array Zen

zen is javascript 1.6 array methods like map and filter.

these are native method in firefox, but they can easily be recreated elsewhere using standard ecma script:

here is a replacement for imho the two most useful ones:
Code:

if (!Array.prototype.map) {// from http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:map
Array.prototype.map = function (fun) {var len = this.length;if (typeof fun != "function") {throw new TypeError;}var res = new Array(len);var thisp = arguments[1];for (var i = 0; i < len; i++) {if (i in this) {res[i] = fun.call(thisp, this[i], i, this);}}return res;};}

if (!Array.prototype.filter) { //from  http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:filter
Array.prototype.filter = function (fun) {var len = this.length;if (typeof fun != "function") {throw new TypeError;}var res = new Array;var thisp = arguments[1];for (var i = 0; i < len; i++) {if (i in this) {var val = this[i];if (fun.call(thisp, val, i, this)) {res.push(val);}}}return res;};}



the real power in these comes from implementing existing and standard function across each element of an array.
you can use anonoumous or pre-defined functions.

You can use the array extra internally to transform HTML collections and other .length containing objects into true arrays.
Compare using the traditional for-next loop to the [].map version, notice the lack of loop code:

Code:

function tags(tagName){
  return Array.prototype.map.apply(
      document.getElementsByTagName(tagName),[
    function(a){return a;}
   ])
}



ok, so the loop is gone. so what? does that really accomplish anything new? No, not really.
It does however give you an array very fast.
what can you do with true arrays?

here is a simple example: i have a function called hide i have used for a while to hide an element.
It accepts one argument, the object or id of the element to hide:

Code:

    function hide(s) {
        if (s.split) {
            s = document.getElementById(s);
        }
        s.style.display = "none";
    }


ok, simple enough, nothing fancy.

but, drawing on the code above, if i already have the 1.6 methods, tags, and hide pre-defined, one-line programming awaits:

Code:

//hide all links 
tags("a").map(hide);

//hide all links that have a title tooltip:
tags("a").filter(function(a){return a.title}).map(hide);



much faster than writing a looping hider script, or customizing a function for a particular page, don’t you think?

Another great benefit of the array extra is the ease at which coercing types can be done.
lets say i have an array filled by text input.value strings that i want to do some math on.
I could write a loop that converts the all to numbers.
if i want it fast, then i need to buffer the length. i also need a buffer array to store the new values, less i corrupt the old one:

Converts an array of string input values into an array of numbers ( for - next ):
Code:

 // 180 chars
var vals = document.getElementsByTagName("input");
var outRay =[];
var mx = vals.length;
for(var i=0; i< mx; i++){
   if (vals[i].value){ outRay[outRay.length] = Number(vals[i]);
}

alert( outRay);




Converts an array of string input values into an array of numbers ( js1.6 ):
Code:

 //70 bytes
alert( tags("input").filter(function(a){return a.value}).map(Number));


so, over twice as brief.

if you just need to convert a predefined array, it’s jokingly simple:

Code:

"432,543,654,63,6452,642,6".split(/\,/g).map(Number);



so to sum, the newer array methods offer several advantages over traditional coding:

  1. code re-use
  2. reduced code length
  3. leveraging existing and native functions
  4. anon functions provide private scope
  5. protects original array
  6. eliminates complications from using custom Object.prototype methods
  7. can increase performance*


*(functions are pre-compiled, native method in firefox).


———————————————-

if you already have a little (or big) library,

the array methods can save you a ton of time by often preventing you from having to customize loop code,
that is the main reason i use them: my impatience.

-$0.02


edit: you can also use these methods on objects by first turning the object into an array of keys,
an array of values, or a two-level array of arrays [[key,[value]] with a simple prototype method.
bonus is that you dont use the old iterations, so prototypes wont interfere with the expected object.
no pollution, mean you can go nuts create powerful array and object prototypes without worrying about “breaking your loops”.

this is also a great way handlle JSON structures.

once you code a few filter and map functions, you can re-use them on many projects, and you really start saving time.