7

So I want an easy way to loop through nodelists, and I always hated that I can't use forEach on nodeLists.

So, now I do: Array.prototype.forEach.call(nodeList, callback).

and for index, i do: Array.prototype.indexOf.call(nodeList, node).

and for pretty much everything I use Array.prototype on nodeLists.

But I'm wondering if these are considered hacks?

Are they the right way to do it?

Also, assuming I don't actually need an array from nodeList, is there an advantage of using Array.from(nodeList).forEach(callback) instead?

3 Answers 3

4

Array.prototype.forEach.call(nodeList, callback) will apply the logic of forEach on the node list. forEach just have a for loop in it that goes from index 0 to this.length and calling a callback on each of the items. This method is calling forEach passing the node list as its this value, since node lists have similar properties of an array (length and 0, 1, ...), everything works fine.

Array.from(nodeList).forEach(callback) will create a new array from the node list, then use forEach on that new array. This second method could be split into two self explanatory lines:

var newArray = Array.from(nodeList);  // create a new array out of the node list
newArray.forEach(callback);           // call forEach on the new array

The first approach is better because it doesn't create additional uneeded resources and it work on node lists directly.

Sign up to request clarification or add additional context in comments.

10 Comments

"The first approach is better because it doesn't create additional uneeded resources and it work on node lists directly!" any perf tests to prove this claim?
@YuryTarabanko Function.prototype.call says ...calls a function with a given this value... thus the node list is passed as this itself! And Array.from says ...creates a new Array instance from an array-like or iterable object!
And? How do you know using dynamic context when calling .forEach doesn't result in some sort of de-optimization? There is nothing "obvious!" when it comes to performance. I mean your claim that "the first approach is better" not the underlying machinery.
@YuryTarabanko Well one can easely observe that the first method is only looping once! The second however is looping twice (one loop for creating a new array out of the node list, the second is when calling forEach on the node list)! So the first method is much more optimized than the second (specially for large node lists or any array-like objects)!
And BTW I'm not arguing that the first method might be faster. I am just trying to convince you that such a claims should only be made based on tests. Both operations have the same Big-O. So you can't simply tell which one is faster using only your imagination and exclamation marks.
|
4

The first method is ES5 compatible:

Array.prototype.forEach.call(nodeList, callback).

The second method uses Array.from which was only defined in ES6:

Array.from(nodeList).forEach(callback)

However, you are not optimising the use of Array.from here, because you first create the whole array, and then iterate over it with forEach.

Instead use the second argument of Array.from:

Array.from(nodeList, callback)

Now the whole operation happens in one iteration.

The nice thing is that in the above expression, the callback is used as a mapping function, so if it returns a value, the whole expression returns the array as defined by those return values. But using this is of course optional. For instance, you could create an array with the text contents of the nodes like this:

texts = Array.from(nodeList, node => node.textContent)

Warning

If you use Array.from with callback, and the node list is a live node list (see NodeList), and you mutate the node list in the callback, then this can have undesired effects. In that case use the two step method where you first turn the node list into an array, and only then perform the callback on its entries.

Comments

2
var array=Array.from(nodeList);
//after some time
var array2=Array.from(nodeList);

If you compare these Arrays youll see that they are not necessarily equal. NodeLists reflect the change of the DOM, as you copy them the arrays stay static. If you want this behaviour / dont care about youre fine. However Array.from is quite new, therefore it isnt understood by older browsers, so it shouldnt be used in productional environments ( if youre not using sth like Babel).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.