Bug 19045 - Consider adding .toArray() on NodeList and HTMLCollection
Consider adding .toArray() on NodeList and HTMLCollection
Status: RESOLVED LATER
Product: HTML WG
Classification: Unclassified
Component: HTML5 spec
unspecified
All All
: P5 enhancement
: ---
Assigned To: This bug has no owner yet - up for the taking
HTML WG Bugzilla archive list
: NoReply
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2012-09-25 21:59 UTC by contributor
Modified: 2012-09-25 22:27 UTC (History)
7 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description contributor 2012-09-25 21:59:25 UTC
This was was cloned from bug 5851 as part of operation LATER convergence.
Originally filed: 2008-07-10 06:53:00 +0000
Original reporter: Ian 'Hixie' Hickson <ian@hixie.ch>

================================================================================
 #0   Ian 'Hixie' Hickson                             2008-07-10 06:53:33 +0000 
--------------------------------------------------------------------------------
From http://alex.dojotoolkit.org/?p=623 :

Fast LiveCollection -> Array Transforms: That many DOM apis return live collections is a bug, but it need not be fatal. Browser vendors could start to provide a simple toArray() method on these live collections to provide a way to “fix” them in place.
================================================================================
 #1   crisp                                           2008-07-10 23:04:05 +0000 
--------------------------------------------------------------------------------
'live collections' are not a bug; they are a design feature and you could use that to your advantage. They are on the other side often misunderstood or not anticipated which could lead to bugs or unexpected results.

On the other hand it is already quite easy to convert such collections to an array in a browser that has implemented Array in a generic way so that it also works on interface objects:

var foo = document.getElementsByTagName('div');
var staticFoo = [].slice.call(foo, 0);

the toArray() could then easily be implemented by prototyping NodeList or HTMLCollection (don't know which one or which browsers actually support that)

I'd rather see a specification that says that Array methods should be generic and thus also work on interface objects (that can be accessed like an array having a length property and all) and that interface objects should be first-class javascript objects and thus be expandable.
================================================================================
 #2   crisp                                           2008-07-11 00:21:14 +0000 
--------------------------------------------------------------------------------
In addition: the performance element brought by alex is just a straw hat; most of the time core JS and DOM operations are just a fraction of dynamic HTML updates. (partial) Document re-rendering is mostly more time consuming.
================================================================================
 #3   Lachlan Hunt                                    2008-07-11 08:03:42 +0000 
--------------------------------------------------------------------------------
(In reply to comment #1)
> 'live collections' are not a bug; they are a design feature and you could use
> that to your advantage.

Even though it's by design, some people consider it a bug because it's very unintuitive.

> On the other hand it is already quite easy to convert such collections to an
> array in a browser that has implemented Array in a generic way so that it also
> works on interface objects:
> 
> var foo = document.getElementsByTagName('div');
> var staticFoo = [].slice.call(foo, 0);


> the toArray() could then easily be implemented by prototyping NodeList or
> HTMLCollection (don't know which one or which browsers actually support that)

It's good to know that it can be so easily provided like that for backwards compatibility, but it's likely that a native implementation would be a bit more efficient.

> I'd rather see a specification that says that Array methods should be generic
> and thus also work on interface objects (that can be accessed like an array
> having a length property and all) and that interface objects should be
> first-class javascript objects and thus be expandable.

This can't work because NodeLists are live (except in Selectors API).  If they weren't live, it would have been possible to consider something like that.

Consider what it would mean for some of the mutator methods of Array to be used directly on a NodeList. e.g.

var foo = document.getElementsByTagName('div');
foo.reverse();
foo.pop();
...

The toArray() method solves this problem, since one can easily do:

var foo = document.getElementsByTagName('div').toArray();

and not have to deal with the NodeList any more.
================================================================================
 #4   crisp                                           2008-07-11 08:20:50 +0000 
--------------------------------------------------------------------------------
If efficiency is key than it makes more sense to add an extra argument to the method that says it's to return a static array iso a live nodelist. That way you're even allowed to do this:

var foo = document.getElementsByTagName('div', RETURN_STATIC_ARRAY).reverse();

:)
================================================================================
 #5   Lachlan Hunt                                    2008-07-11 08:59:21 +0000 
--------------------------------------------------------------------------------
(In reply to comment #4)
> If efficiency is key than it makes more sense to add an extra argument to the
> method that says it's to return a static array iso a live nodelist. That way
> you're even allowed to do this:
> 
> var foo = document.getElementsByTagName('div', RETURN_STATIC_ARRAY).reverse();

That's not backwards compatible and makes it more difficult for JS libraries to provide the functionality in legacy browsers.  It would require the script to do replace the method itself, check for the extra paramter and return an array.

document._getElementsByTagName = document.getElementsByTagName;
document.getElementsByTagName = function(tagName, static) {
  var list = document._getElementsByTagName(tagName);
  if (static) {
    var array = [].slice.call(foo, 0);
    return array;
  }
  return list;
}

That would also have to be done separately for every other existing and future method that returns a NodeList on both document and the element nodes.  Adding a single method that deals with all node lists regardless of where they come from is much easier to implement and use.
================================================================================
 #6   crisp                                           2008-07-11 09:49:24 +0000 
--------------------------------------------------------------------------------
The same goes for toArray(), you do need to implement switching logic anyway because this simply will not work either:

var foo = document.getElementsByTagName('div').toArray();

and afaik there is no way in legacy browsers to make this work since one browser doesn't support expando's on interface objects *at all* and I can't even make this work in at least Firefox:

if (!HTMLCollection.prototype.toArray)
{
 HTMLCollection.prototype.toArray = function()
 {
  return [].slice.call(this, 0);
 }
}

(assuming this is the right object, I tried NodeList too for good measure)

the only option is to prototype toArray on Object, and we all know that that's not good practice.

Imo a generic toArray method for live nodelists is just syntax sugering and doesn't really solve the problem of the concept of live nodelists being unintuitive; you will need to know about the fact anyhow to know that you can use toArray() (in some unforeseeable future).

And like I said: if performance is key a native toArray method is far less performant than an extra argument. And how much will it's performance gain be over [].slice.call? Will that be worth the trouble?
================================================================================
 #7   Ian 'Hixie' Hickson                             2009-05-24 01:07:51 +0000 
--------------------------------------------------------------------------------
In the interests of not getting ahead of the implementations, I'm going to punt on this for now. I think it makes sense to do something like this (I've even suggested the same myself years ago).
================================================================================
 #8   Maciej Stachowiak                               2010-03-14 13:15:11 +0000 
--------------------------------------------------------------------------------
This bug predates the HTML Working Group Decision Policy.

If you are satisfied with the resolution of this bug, please change the state of this bug to CLOSED. If
you have additional information and would like the editor to reconsider, please reopen this bug. If you would like to escalate the issue to the full HTML Working Group, please add the TrackerRequest keyword to this bug, and suggest title and text for the tracker issue; or you may create a tracker issue yourself, if you are able to do so. For more details, see this document:
   http://dev.w3.org/html5/decision-policy/decision-policy.html

This bug is now being moved to VERIFIED. Please respond within two weeks. If this bug is not closed, reopened or escalated within two weeks, it may be marked as NoReply and will no longer be considered a pending comment.
================================================================================