W3C home > Mailing lists > Public > www-dom@w3.org > October to December 2011

Re: toArray() method for array-like DOM list objects

From: Boris Zbarsky <bzbarsky@MIT.EDU>
Date: Thu, 22 Dec 2011 18:07:19 -0500
Message-ID: <4EF3B827.2080501@mit.edu>
To: "Marat Tanalin | tanalin.com" <mtanalin@yandex.ru>
CC: www-dom@w3.org
On 12/22/11 5:41 PM, Marat Tanalin | tanalin.com wrote:
> 22.12.2011, 23:05, "Boris Zbarsky"<bzbarsky@MIT.EDU>:
>> On 12/22/11 1:51 PM, Marat Tanalin | tanalin.com wrote:
>>
>>>   At least since it uses some function with dummy argument
>>
>> What dummy argument?
>
> I mean 0 (zero) -- second argument passed to Array.prototype.slice.call() and used as first and only argument for called slice().

You don't need that.  Array.prototype.slice.call(nodelist) works fine, 
because |ToInteger(undefined) === 0|.  See ECMA-262 section 15.4.4.10.


> For example, people who don't [fully] understand how does this conversion method work could answer a question like "Why should this zero be passed to slice() function every time if it should be enough to pass just array-like object to convert itself?".

See above.

>> That would simply be an implementation bug.  One which toArray may well
>> share if it were implemented.
>
> Of course, performance depends on implementation. However I still tend to believe that indirect (with call()) calling a function (Array.prototype.slice()) with passing some arguments (DOM list object itself, and zero) to it should be quite probably slower than just direct calling a method for object (domList.toArray()) without arguments.

I tend to be very skeptical of faith-based performance claims not backed 
up with measurement or profiling....

What toArray has to do in most UAs is to call from JS into C++, then 
using C++ APIs to the JS engine create an array, fill it with JS objects 
corresponding to the nodes, etc.

What slice() has to do is to get the objects corresponding to the nodes 
out of the nodelist (which is already fast-pathed in UAs because web 
code does it) and then put them in an array object.

Which one is faster in practice depends on the overhead of the APIs used 
for toArray above as compared to the JS-engine-internal APIs that can be 
used when creating the array via slice(), as well as on the relative 
cost of getting the right JS objects in both approaches.  I won't even 
guess as to which of those is faster.  I do think that if I were 
implementing toArray in Gecko, I would be likely to just reuse some of 
the slice() code.

>> I'm almost willing to buy "clear" and "straightforward".  Except that it
>> would only work for some objects but not others, whereas slice() works
>> for any array-like.  So you'd have to know exactly what sort of object
>> you have to use it; in practice this would be a huge pain I suspect.
>
> Could you provide an example of such object where slice() works, but toArray() would not?

Sure.  A JS array object.  Or this object:

   { length: 2, 0: "a", 1: "b" }

> Theoretically _all_ array-like objects that currently can be converted to Array using Array.prototype.slice.call() should have toArray() method.

"array-like" in this context means "has a property named 'length'".

> It would be enough to have this ability for DOMNodeList and DOMTokenList only, though. I doubt that inability to call toArray() for literally _any_ object could be an issue in real-world usecases.

It would mean that code which currently uses Array.prototype.slice and 
can take as input either arrays or nodelists (common in JS libraries) 
would need to either keep using Array.prototype.slice or check what its 
argument is.

> Each object type has its own API based on what's expected (and is documented on MDN in particular) from the specific objects, it's perfectly OK.

I doubt you're really appreciate NodeList and HTMLCollection having 
different APIs, even if they were documented...

> Passing DOM list to Array constructor would probably be ambiguous since DOM list object itself can represent a single Array item

This ambiguity already exists for numbers, yes?  Why is a separate 
argument not needed there, apart from the "it's always been that way" 
argument.

> We could probably do something like Array.import(domList) instead, but it seams to be still questionable whether this would be really better than toArray() method applied directly to DOM list object itself.

It would be better for cases when you're working with arbitrary 
arraylikes which may or may not be nodelists, for sure.

-Boris
Received on Thursday, 22 December 2011 23:07:48 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Friday, 22 June 2012 06:14:08 GMT