NodeList and HTMLCollection are not arrays

516 views
Skip to first unread message

Jake Verbaten

unread,
Oct 29, 2011, 7:44:06 AM10/29/11
to jquery-s...@googlegroups.com
[NodeList][1] and [HTMLCollection][2] are not arrays.

This is a right pain in the ass since they are array like objects but lack all the manipulation methods.

This leads to me writing code like `var els = toArray(el.getElementsByTagName("div"));`

Now I know making these host objects arrays is going to be a pain for implementations and will probably break the internet (I say to hell with bad code, purge with fire!)

As a sidenote there may be other collection objects not defined in DOM4 that should also be arrays. 

As a futher sidenote making ES arrays lives may be epic pain.

Dave Methvin

unread,
Oct 29, 2011, 9:47:57 AM10/29/11
to jquery-s...@googlegroups.com

[NodeList][1] and [HTMLCollection][2] are not arrays.

They also don't have JavaScript Array semantics, though:


The key word there is *live*, if you change the document the underlying collection changes as well. It's worked that way forever. Arrays don't do that.

Jake Verbaten

unread,
Oct 29, 2011, 9:50:49 AM10/29/11
to jquery-s...@googlegroups.com
Yes they are live, it would be a right pain to make an array live. 

My phrasing was vague. I dont want nodelist to _be_ an array. I would like to behave like an array (including all the methods).

Rick Waldron

unread,
Oct 29, 2011, 10:33:57 AM10/29/11
to jquery-s...@googlegroups.com
FWIW, I've been working with Dave Herman at Mozilla on two Array construction extensions for ES.next 


Take a look at Array.from( arraylike )

These will have the benefit of native/host optimization, while _not_ breaking the web.

Rick

Jake Verbaten

unread,
Oct 29, 2011, 11:26:26 AM10/29/11
to jquery-s...@googlegroups.com
I use something similar to `Array.from` (I call it `toArray`) however the exact problem is that calling such a function on every NodeList and HTMLCollection is a right pain in the ass.

Rick Waldron

unread,
Oct 29, 2011, 11:37:37 AM10/29/11
to jquery-s...@googlegroups.com
Of course and ideally it would be as optimized as possible.

Proxies _should_ allow for real Array subclasses




T.J. Crowder

unread,
Oct 30, 2011, 3:01:23 PM10/30/11
to jQuery Standards
On Oct 29, 1:50 pm, Jake Verbaten <rayn...@gmail.com> wrote:
> Yes they are live, it would be a right pain to make an array live.
>
> My phrasing was vague. I dont want nodelist to _be_ an array. I would like
> to behave like an array (including all the methods).

So for instance:

var nl = document.getElementsByTagName("span");
nl.splice(10, 3, document.createElement('span'));

...should remove the 11th, 12th, and 13th elements and then add in a
blank one? Lots of failure modes and complexity to deal with there,
such as:

var nl = document.getElementsByTagName("span");
nl.splice(10, 3, document.createElement('div'));

Is that an error? It's a *live* `NodeList` of spans, after all, so
adding a div to it seems like an error...

I think trying to require JavaScript `Array` semantics on `NodeList`
objects (which can, of course, be used from other languages) is mixing
problem domains, which is usually not a good idea.

Now, if there are some specific high-value functions you'd like to add
to `NodeList`, that might be a different matter...
--
T.J. Crowder
Independent Software Engineer
tj / crowder software / com
www / crowder software / com

Jake Verbaten

unread,
Oct 30, 2011, 3:29:19 PM10/30/11
to jquery-s...@googlegroups.com


I think trying to require JavaScript `Array` semantics on `NodeList`
objects (which can, of course, be used from other languages) is mixing
problem domains, which is usually not a good idea.

Bah! I forgot the DOM is meant to be used in Java :(

Ok making nodelist behave like an array doesn't make sense. Instead we should have es standardize a `Array.From` or `toArray` method

Rick Waldron

unread,
Oct 30, 2011, 4:17:08 PM10/30/11
to jquery-s...@googlegroups.com
The ball is well in motion on Array.from() 

:)

Jake Verbaten

unread,
Oct 30, 2011, 5:34:34 PM10/30/11
to jquery-s...@googlegroups.com
I can't find a harmony or strawman proposal for Array.from() however I can see the Array static methods which would solve the problem just as well. 

The Configurator

unread,
Nov 3, 2011, 1:47:57 PM11/3/11
to jquery-s...@googlegroups.com
I just want to say that Array.from() makes for code that is quite a lot less readable than toArray().

Rick Waldron

unread,
Nov 3, 2011, 2:03:14 PM11/3/11
to jquery-s...@googlegroups.com
I'm sorry that you feel that way, but the color of the bikeshed has already been determined.

"toArray" as a function property of the global object would conflict with userland code. 

Rick Waldron

unread,
Nov 3, 2011, 2:55:02 PM11/3/11
to jquery-s...@googlegroups.com
You couldn't find it, because it did not yet exist.



Rick

The Configurator

unread,
Nov 3, 2011, 9:00:27 PM11/3/11
to jquery-s...@googlegroups.com
I didn't think it should be a function of the global object. It should be a function of NodeArray et al.

Any global function (rather than a method call) generally makes code behave a bit backwards.

selectSomeNodeList().toArray().map(function (node) { node.doSomething(); })
would look a lot more straightforward than
Array.from(selectSomeNodeList()).map(function (node) { node.doSomething(); })

Rick Waldron

unread,
Nov 3, 2011, 10:32:35 PM11/3/11
to jquery-s...@googlegroups.com
What is "NodeArray"? Do you mean NodeList?

On Thu, Nov 3, 2011 at 9:00 PM, The Configurator <config...@gmail.com> wrote:
I didn't think it should be a function of the global object. It should be a function of NodeArray et al.

Any global function (rather than a method call) generally makes code behave a bit backwards.

selectSomeNodeList().toArray().map(function (node) { node.doSomething(); })
Only temporarily transforms selectSomeNodeList() to an array, likely won't work with live NodeList semantics - what happens if selectSomeNodeList() is returning a document.getElementsByTagName and that list changes while map(...) is iterating?
 
would look a lot more straightforward than
Array.from(selectSomeNodeList()).map(function (node) { node.doSomething(); })

Produces a brand new Array instance based on the _current_ returned object value of selectSomeNodeList()


Additionally, for .toArray() method to be as effective as Array.from(), you'd have to implement it as a prototype method higher up the chain to avoid redefining the same method more then once. The arguments, NodeList and DOMTokenList objects' closest prototype is Object.prototype - which means you'd have to extend Object.prototype and no standards body is interested in doing that.

Array.from() is an Array() constructor that will create and return new Array instances from non-Array objects, not to temporarily coerce an object into an Array form (as a toArray() method would imply, if we're sticking to the semantics of non mutation eg. toString() )

Rick

The Configurator

unread,
Nov 3, 2011, 10:54:15 PM11/3/11
to jquery-s...@googlegroups.com
Oops, I meant NodeList of course.

Does the value returned from toString change when the DOM does? Of course not, it's a string - much the same should the value returned from toArray() be a static array created from the node list.

Is adding the same method to two objects' prototypes really that bad?

NodeList.prototype.toArray = DOMTokenList.prototype.toArray = function () { ... }

All that said, I think this discussion is a bit moot, if as you said before, "the color of the bikeshed has already been determined".
Reply all
Reply to author
Forward
0 new messages