Is there a more efficient way to convert an HTMLCollection to an Array, other than iterating through the contents of said collection and manually pushing each item into an array?
var arr = Array.prototype.slice.call( htmlCollection )
will have the same effect using "native" code.
Edit
Since this gets a lot of views, note (per @oriol's comment) that the following more concise expression is effectively equivalent:
var arr = [].slice.call(htmlCollection);
But note per @JussiR's comment, that unlike the "verbose" form, it does create an empty, unused, and indeed unusable array instance in the process. What compilers do about this is outside the programmer's ken.
Edit
Since ECMAScript 2015 (ES 6) there is also Array.from:
var arr = Array.from(htmlCollection);
Edit
ECMAScript 2015 also provides the spread operator, which is functionally equivalent to Array.from
(although note that Array.from
supports a mapping function as the second argument).
var arr = [...htmlCollection];
I've confirmed that both of the above work on NodeList
.
A performance comparison for the mentioned methods: http://jsben.ch/h2IFA
[].slice.call(htmlCollection)
also works. –
Sisley Array.from
, i.e. from
, is not supported by IE11. –
Spitfire Array.prototype.slice
is not normally used this way. Instead, you would call it as a method on an array like [3, 5, 7].slice()
. That creates and returns a new Array based on the indexes passed to slice
. When you pass no arguments, it copies the whole array. HTML collections don't have Array
in their prototype chain, so you can't use the slice
method on references to them. However, if you use call()
(which is on Function.prototype
) to invoke Array.prototype.slice
on an array-like object, it accomplishes the same thing. Hope this helps! –
Microscopy [...htmlColl].forEach((i)=>{//do})
–
Sandeesandeep [Symbol.iterator]()
method. –
Jog [... htmlCollection as unknown as Element[]]
–
Overdress []
as result when converting a HTMLColl to Array. The Collection though has elements and can be consolelogged as a whole, but not each element. –
Parasang typeof(arr)
as object. –
Gladygladys not sure if this is the most efficient, but a concise ES6 syntax might be:
let arry = [...htmlCollection]
Edit: Another one, from Chris_F comment:
let arry = Array.from(htmlCollection)
Array.from()
–
Emeric Array.from
, i.e. from
, is not supported by IE11. –
Spitfire I saw a more concise method of getting Array.prototype
methods in general that works just as well. Converting an HTMLCollection
object into an Array
object is demonstrated below:
[].slice.call( yourHTMLCollectionObject );
And, as mentioned in the comments, for old browsers such as IE7 and earlier, you simply have to use a compatibility function, like:
function toArray(x) {
for(var i = 0, a = []; i < x.length; i++)
a.push(x[i]);
return a
}
I know this is an old question, but I felt the accepted answer was a little incomplete; so I thought I'd throw this out there FWIW.
For a cross browser implementation I'd sugguest you look at prototype.js $A
function
function $A(iterable) {
if (!iterable) return [];
if ('toArray' in Object(iterable)) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}
It doesn't use Array.prototype.slice
probably because it isn't available on every browser. I'm afraid the performance is pretty bad as there a the fall back is a javascript loop over the iterable
.
$A
function does most of the time. –
Cleodel This works in all browsers including earlier IE versions.
var arr = [];
[].push.apply(arr, htmlCollection);
Since jsperf is still down at the moment, here is a jsfiddle that compares the performance of different methods. https://jsfiddle.net/qw9qf48j/
var args = (htmlCollection.length === 1 ? [htmlCollection[0]] : Array.apply(null, htmlCollection));
–
Gruchot I suppose that calling Array.prototype
functions on instances of HTMLCollection
is a much better option than converting collections to arrays (e.g.,[...collection]
or Array.from(collection)
), because in the latter case a collection is unnecessarily implicitly iterated and a new array object is created, and this eats up additional resources. Array.prototype
iterating functions can be safely called upon objects with consecutive numeric keys starting from [0]
and a length
property with a valid number value of such keys' quantity (including, e.g., instances of HTMLCollection
and FileList
), so it's a reliable way. Also, if there is a frequent need in such operations, an empty array []
can be used for quick access to Array.prototype
functions. A runnable example:
alert(
Array.prototype.reduce.call(
document.querySelector('ol').children,
(acc, { textContent }, i) => `${acc}${i + 1}) ${textContent}` + `\n`,
'',
),
);
<ol>
<li>foo</li>
<li>bar</li>
<li>bat</li>
<li>baz</li>
</ol>
To convert array-like to array in efficient way we can make use of the jQuery makeArray
:
makeArray: Convert an array-like object into a true JavaScript array.
Usage:
var domArray = jQuery.makeArray(htmlCollection);
A little extra:
If you do not want to keep reference to the array object (most of the time HTMLCollections are dynamically changes so its better to copy them into another array, This example pay close attention to performance:
var domDataLength = domData.length //Better performance, no need to calculate every iteration the domArray length
var resultArray = new Array(domDataLength) // Since we know the length its improves the performance to declare the result array from the beginning.
for (var i = 0 ; i < domDataLength ; i++) {
resultArray[i] = domArray[i]; //Since we already declared the resultArray we can not make use of the more expensive push method.
}
What is array-like?
HTMLCollection is an "array-like"
object, the array-like objects are similar to array's object but missing a lot of its functionally definition:
Array-like objects look like arrays. They have various numbered elements and a length property. But that’s where the similarity stops. Array-like objects do not have any of Array’s functions, and for-in loops don’t even work!
This is my personal solution, based on the information here (this thread):
var Divs = new Array();
var Elemns = document.getElementsByClassName("divisao");
try {
Divs = Elemns.prototype.slice.call(Elemns);
} catch(e) {
Divs = $A(Elemns);
}
Where $A was described by Gareth Davis in his post:
function $A(iterable) {
if (!iterable) return [];
if ('toArray' in Object(iterable)) return iterable.toArray();
var length = iterable.length || 0, results = new Array(length);
while (length--) results[length] = iterable[length];
return results;
}
If browser supports the best way, ok, otherwise will use the cross browser.
[,,]
becomes [undefined, undefined]
. –
Compossible Sometimes, Even You have written code the correct way, But still it doesn't work properly.
var allbuttons = document.getElementsByTagName("button");
console.log(allbuttons);
var copyAllButtons = [];
for (let i = 0; i < allbuttons.length; i++) {
copyAllButtons.push(allbuttons[i]);
}
console.log(copyAllButtons);
you get empty array. Like, This
HTMLCollection []
[]
For Solving this problem, You have to add link of javascript file after body tag in html file.
<script src="./script.js"></script>
As you can see below, html_file
Final Output
HTMLCollection(6) [button.btn.btn-dark.click-me, button.btn.btn-dark.reset, button#b, button#b, button#b, button#b, b: button#b]
(6) [button.btn.btn-dark.click-me, button.btn.btn-dark.reset, button#b, button#b, button#b, button#b]
I'm not sure about efficiency but, from a purely aesthetic point of view, I find this pleasing.
HTMLCollection.prototype.toArray = function() { return Array.from(this); }
now you can use it like this.
document.getElementsByClassName('tax-status').toArray().forEach(console.log);
© 2022 - 2024 — McMap. All rights reserved.
for (var a=[], i=collection.length; i;) a[--i] = collection[i];
so not much of a "con" there :-) – CompossibleArray.prototype.slice.call
and Brave (based on Chrome 59.0.3071) has virtually no difference between the two javascript tests over multiple runs. See jsperf.com/htmlcollection-array-vs-jquery-children – Gossamer