Concat works with ordinary numerical and string arrays but doesn't with object arrays.
Actually, it does, but NodeList
instances don't have a concat
method, and Array#concat
doesn't have a means of identifying that you want to flatten those (because they're not arrays).
But it's still fairly easy to do (see caveat below, though). Change this line:
var allTags = allInputs.concat(allSelects);
to
var allTags = [];
allTags.push.apply(allTags, allInputs);
allTags.push.apply(allTags, allSelects);
Live Example | Source
That works by using a bit of a trick: Array#push
accepts a variable number of elements to add to the array, and Function#apply
calls the function using the given value for this
(in our case, allTags
) and any array-like object as the arguments to pass to it. Since NodeList
instances are array-like, push
happily pushes all of the elements of the list onto the array.
This behavior of Function#apply
(not requiring the second argument to really be an array) is very clearly defined in the specification, and is well-supported in modern browsers.
Sadly, IE6 and 7 don't support the above (I think it's specifically using host objects — NodeLists
— for Function#apply
's second argument), but then, we shouldn't be supporting them, either. :-) IE8 doesn't, either, which is more problematic. IE9 is happy with it.
If you need to support IE8 and earlier, sadly, I think you're stuck with a boring old loop:
var allInputs = document.getElementsByTagName('input');
var allSelects = document.getElementsByTagName('select');
var allTags = [];
appendAll(allTags, allInputs);
appendAll(allTags, allSelects);
function appendAll(dest, src) {
var n;
for (n = 0; n < src.length; ++n) {
dest.push(src[n]);
}
return dest;
}
Live Example | Source
That does work on IE8 and earlier (and others).