My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Sunday, April 19, 2009

[COW] A Generic ArrayObject Converter

Few days ago I wrote about a fast Array slice implementation for every browser, a callback able to convert "every collection" into an Array.
For collection, I mean every instance with a length attribute and an index access Array like. This object, for example, could be considered as a collection:

var generic = {
length: 2,
"0": "abc",
"1": "def"
};

Above instance is a basic model of most common libraries such jQuery, prototype, base, and every other based over an Array like prototype.

Some library could coexist in the same page without problems but not every library implement a method to create a copy of another collection into a new instance of the library itself.
As example, a jQuery or Sizzle result into another instance, a generic DOM collection into a jQuery object, etc etc.
All these instances could be passed via Array.prototype.push to be populated, and thanks to this peculiarity we can obtain every kind of instance from a collection via Array conversion.

var toArrayObject = (function(push, e){
// WebReflection - Mit Style License
e.base = {length:0};
e.slice = (function(slice){
// portable slice
try {
slice.call(document.childNodes);
var $slice = slice;
} catch(e) {
var $slice = function(begin, end){
if(this instanceof Object)
return slice.call(this, begin || 0, end || this.length);
for(var i = begin || 0, length = end || this.length, len = 0, result = []; i < length; ++i)
result[len++] = this[i];
return result;
};
};
return $slice;
})(Array.prototype.slice);

// prototype ready callback
return function(constructor){

// assign the "class" prototype or the base object
// as anonymous prototype
e.prototype = constructor ? constructor.prototype : e.base;

// create a new instance of anonymous
var r = constructor === Array ? [] : new e;

// inject via push the collection, passed as function scope
push.apply(r, e.slice.call(this));

// return the new ArrayObject instance
return r;
};
})(
Array.prototype.push,
function(){}
);

With above code we could quickly transform, for example, a DOM collection into a jQuery instance without using the jQuery engine:


var result = toArrayObject.call(
document.getElementsByTagName("div"),
jQuery
);

result.remove();


Another example could be a transformation between jQuery and prototype:

var prototyped = toArrayObject.call(jQuery(".test"), $);


The same could be obviously done via Array, even if this is a non-common case:

toArrayObject.call([1, 2, 3], jQuery);
toArrayObject.call(jQuery(".test"), Array);


The usage of call makes prototype assignment that simple:

jQuery.fn.convertTo = toArrayObject;

// as prototype or other library conversion
jQuery(".test").convertTo($);


That's it, if you never wondered about elements injections, libraries conversions, or Array like object management, this code could be a truly quick and portable solution.

No comments: