[whatwg] Adding ECMAScript 5 array extras to HTMLCollection

Jonas Sicking jonas at sicking.cc
Fri Jul 30 04:18:41 PDT 2010


On Thu, Jul 29, 2010 at 5:45 PM, Ian Hickson <ian at hixie.ch> wrote:
>
> The e-mails quoted below consist of the salient points of this thread:
>
> On Fri, 23 Apr 2010, David Bruant wrote:
>>
>> Make that HTMLCollection (and all HTML*Collection, as a consequence of
>> inheritence of HTMLCollection) inherit from the ECMAScript Array
>> prototype. This way, it will make available all Array extra methods
>> (forEach, map, filter...) added in ECMAScript5 (and next versions which
>> should go in the same direction).
>>
>> As far as I know, adding this won't break any existing code. The
>> semantics of a Collection and the way it is used is very close from
>> ECMAScript Arrays. I don't think that the notion of "live object" and
>> ECMAScript Array are incompatible either. Once again, I am talking about
>> ECMAScript binding. I have no intention to touch the HTMLCollection
>> interface or other languages bindings.
>
> On Sun, 25 Apr 2010, J Z wrote:
>>
>> If HTMLCollection was inheriting from Array, and methods like `forEach`,
>> `map`, etc. were to operate on a live object, there would definitely be
>> undesired consequences. We can see this in, say, Firefox (which allows to
>> set [[Prototype]] of `HTMLCollection` to `Array.prototype`):
>>
>> HTMLCollection.prototype.__proto__ = Array.prototype;
>>
>> document.getElementsByTagName('div').forEach(function(el) {
>>   el.parentNode.removeChild(el); // doesn't work as expected
>> });
>>
>> // turning live collection into static array fixes this
>> Array.slice(document.getElementsByTagName('div')).forEach(function(el) {
>>   el.parentNode.removeChild(el);
>> });
>
> On Sat, 24 Apr 2010, David Bruant wrote:
>>
>> I think I can take your point as a "pro" more than a "con", because in
>> ES5, right before the definition of each array extra method, a paragraph
>> like the following can be found :
>>
>> "The range of elements processed by forEach is set before the first call
>> to callbackfn. Elements which are appended to the array after the call
>> to forEach begins will not be visited by callbackfn. If existing
>> elements of the array are changed, their value as passed to callback
>> will be the value at the time forEach visits them; elements that are
>> deleted after the call to forEach begins and before being visited are
>> not visited."
>>
>> This point is confirmed by every algorithm where the length is "saved"
>> once for all before the loop and not got from the .length property each
>> time.
>
> On Mon, 26 Apr 2010, Erik Arvidsson wrote:
>> On Sun, Apr 25, 2010 at 01:07, David Bruant wrote:
>> > Le 25/04/2010 00:39, J Z a écrit :
>> >>
>> >> I have thought a lot about weirdnesses that people could think about
>> >> like trying to assign a value to the HTMLCollection (divs[14] =
>> >> myOtherDiv), but once again, it wouldn't be more allowed than it
>> >> currently is (I have no idea of what happens today, but if an error
>> >> is thrown in a for-loop, it should throw an error as well in a call
>> >> within a forEach).
>> >
>> > How would destructive methods like `push` or `sort` behave? Would
>> > `document.body.childNodes.push(document.createTextNode('foo'))` append
>> > text node to a body element? Or would it be a noop?
>> >
>> > That is actually a very good point. It think that the behavior should
>> > be exactly the same as "an equivalent without array methods". (this
>> > point of my proposal would need to be made completly explicit for each
>> > method)
>>
>> One way to solve this could be to split Array into two interfaces. One
>> to be used with immutable array like objects and one to use to mutate
>> objects. Then we could apply the immutable array like interface to
>> NodeList and its related interfaces. The benefit of doing that is that
>> NodeList.prototype.push would be undefined instead of failing when
>> called.
>
> On Mon, 26 Apr 2010, David Flanagan wrote:
>>
>> Rather that trying to make DOM collections feel like arrays, how about
>> just giving them a toArray() method?  This makes it clear that a
>> collection is not an array, but clearly defines a way to obtain an
>> array.  Clever implementors might even be able to optimize common
>> uses-cases using some kind of copy-on-write strategy so that toArray()
>> doesn't involve memory allocation and copying.
>>
>> Of course, trying to teach programmers when they ought to call toArray()
>> and when it is not necessary is another matter.  Perhaps calling the
>> method snapshot() and focusing on the live vs. static distinction
>> instead of the fake array vs. true array distinction would invite less
>> misuse.
>>
>> Or we can just leave the DOM as it is and get used to calling the
>> equivalent of Prototype's $A() function.
>
> Before changing something this substantial, I'd like to have implementor
> feedback regarding what the best way to address this is:
>
>  - somehow make HTMLCollections and NodeLists inherit from Array?
>
>  - define a bunch of feature on HTMLCollections and NodeLists so that
>   they're like arrays?

I don't think this makes sense given the immutability of NodeLists.

>  - provide a toArray() method or equivalent?

I think this would make sense, though I think it's also worth
supplying functions that apply array-like operations directly on the
nodelist. To avoid the overhead of copying the data.

>  - do nothing?

Given how often this comes up, I think it's worth addressing this.

>  - something else?

John Resig has been working on something in this area. I don't know if
that's ready to publish yet though.

/ Jonas


More information about the whatwg mailing list