I’ve been working on a function to convert nodeList and object properties to an array.
The first question is with regards IE and checking whether the object provided is an HTML collection.
The best I have come up with so far, is to test if it’s an object, has an ‘item’ which is a function and has length.
Can this be improved upon?
The second question is with regards slice.call and a while loop copy. I guess I need to do some profile/timing tests, but I’m wondering if the function merits a slice.call? or should I simplify?
Any advice greatly appreciated.
// Some weirdness in IE regarding nodesList and typeof 'item' returning 'Object'
// even though when alerted it returns 'function (){...}'.
// Therefore having to use regExp.test() to check whether it's a function instead.
// Note: _isNodeList isn't full proof. An object with the properties
// {length: x, item : function(){}} will pass and return length.
var _isNodeList = function(obj){
var objType = {}.toString.call(obj);
return (objType === '[object NodeList]' ||
objType === '[object HTMLCollection]' ||
objType === '[object Object]' && /^\\s?function/.test(obj.item))
&& obj.length; // returns length of nodeList if true
};
var _toString = {}.toString,
_slice = [].slice;
// ------- toArray -------
var toArray = function (obj /* HTMLCollection or Object */){
var copy = [],
len = _isNodeList(obj),
oType = _toString.call(obj);
if (len){
try {
copy = _slice.call(obj); return copy;
}
catch(e) {
while (len--) copy[len] = obj[len]; return copy;
}
} else if ( oType === '[object Object]' ){
for (var prop in obj){
if (obj.hasOwnProperty(prop)) copy.push(obj[prop]);
}
return copy;
}
throw new TypeError ( 'Object type ' + oType + ' not supported!!' );
};
Tests
var obj = {length : 2, x : 3};
alert(toArray(obj)); // [2,3]
// An HTML unordered list.
var liNodeList = document.getElementsByTagName('li');
alert(toArray(liNodeList)); // [[object HTMLLIElement],[object HTMLLIElement],...,[object HTMLLIElement]]
var liItems = toArray(liNodeList);
try { liItems.forEach(function(el){ el.style.color = 'red'; }); } catch(e){}; // IE has no built-in array.forEach.
var obj2 = {length : 2, item : function(){}};
alert(toArray(obj2)); // [,] No Good!!
ps. Oh and what’s happened to crMalibu?