2

Lots of JavaScript libraries (jQuery, Zepto) seem to be calling Array.prototype.slice.call on querySelectorAll(), getElementsByTag or ClassName results...

From reading many many similar questions/answers on StackOverflow I do understand that its to convert a NodeList result to a real Array so that you can invoke Array methods (slice, pop) on the results which are not available on NodeLists - but what I don't understand is why? You don't usually really need slice/pop on a list of DOM nodes + NodeLists already have a length property so they're traversable anyway.

Some answers seem to imply that its because a NodeList is pointing to live DOM objects. But again if you convert it to an Array, the references are still pointing to live DOM nodes - so whats the difference?

Or is it something else that I'm completely missing? Does it help Zepto/jQuery to somehow cache multiple property calls for DOM elements? (although I don't really see how since those are still live DOM references)

14
  • 1
    You're right that a NodeList is pointing to live DOM objects, but that means that when one is destroyed (or is no longer a valid item for the list), it and its spot is removed from the list. When you slice into an array, it's not the same "live" list - the elements themselves are live, but not the list itself. When an item is destroyed, its place is still kept in the array...but it won't represent the element - I'm guessing it becomes undefined or null.
    – Ian
    Commented Nov 8, 2012 at 18:36
  • @Ian if an array contains a reference to a DOM node then that node cannot be garbage collected.
    – Alnitak
    Commented Nov 8, 2012 at 18:37
  • @Alnitak I see, well then I guess my comment would be changed to say something like ", its place is still kept in the array and the element stays, until there are no more references to it...then the value in the array would be undefined or null". Would that be correct?
    – Ian
    Commented Nov 8, 2012 at 18:41
  • @Ian no, that wouldn't be correct because the element cannot have "no more references" because there's still one in the array!. The only way to avoid that is to explicitly set the array element to something else, so that the array no longer holds that reference,
    – Alnitak
    Commented Nov 8, 2012 at 18:44
  • Ah I see - yes, thanks thats certainly a plausible explanation... although - wouldn't that be a bad thing? I mean this would mean that a converted array would still maintain a reference to a DOM element that has potentially been removed - thus flagging it as "still in use" and signalling to the garbage collector that it shouldn't be removed from memory? Commented Nov 8, 2012 at 18:45

2 Answers 2

2

You don't usually really need slice/pop on a list of DOM nodes

Actually, you do, and that's exactly why it's necessary.

For example, how else would .eq(), .first(), etc. work. The jQuery object contains a copy of the NodeList in an array, and then the individual methods take slices of that array. Similarly, you can't .add() nodes to a NodeList.

Furthermore, those arrays need to remain valid even if the elements therein are subsequently removed from the DOM. The references in the array are still valid, and can be used to reinsert those elements back into the DOM.

If all you had was a live NodeList the elements would automagically disappear from the list when they're removed from the DOM, and would be lost forever unless you had a separate reference to them.

2
  • @TinyGiant some NodeList objects are live, some are static. The one returned by querySelectorAll is static. Suggest you read the substantial comment thread on the question above.
    – Alnitak
    Commented Sep 8, 2015 at 9:42
  • Note that Array.prototype.slice.call(nodeList) is not working on some IE versions if the nodeList is an SVG element Commented Sep 30, 2015 at 14:33
0

...because a NodeList is pointing to live DOM objects...

No, this is a misunderstanding. The key is not that each of the nodes in the list is a "live" DOM object (true but irrelevant), it's that the list itself is "live" . In other words the contents of the list may change (or even grow or shrink) at any time whenever the DOM is changed.

If you perform operations on the items in the list that change the DOM, the list itself may change on the fly while you're using it. That means under the covers your code can get into really weird recursion and/or performance problems, without you realizing it and without hardly any indication in the source code.

Converting the NodeList to a regular Javascript Array removes this "liveness" of the list itself, and thus removes the opportunity to shoot yourself in the foot.

1
  • @TinyGiant Some certainly are, e.g. aNode.childNodes. Your example uses querySelectorAll which returns a non-live NodeList.
    – 1983
    Commented Sep 8, 2015 at 10:30

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.