[whatwg] Adding ECMAScript 5 array extras to HTMLCollection

Alex Russell slightlyoff at google.com
Fri Jul 30 14:46:13 PDT 2010


On Fri, Jul 30, 2010 at 4:18 AM, Jonas Sicking <jonas at sicking.cc> wrote:
> 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.

Wait...what? Shouldn't some sort of NodeList be mutable? And shouldn't
JS support immutable Arrays? We need to fix both of these APIs, and we
keep heaping back-pressure on JavaScript's Array without any
reasonable resolution because we're not exploring how to make Array
subtypes work as we want them to for all the use cases (like this)
that we care to express.

>>  - 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.

Elided if they're *actual* Arrays.

>>  - 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.

I'd like to see any proposal in this area include NodeLists that are
*real* Array subtypes. Anything that's not is a missed opportunity
both for this list and for TC39.

Regards


More information about the whatwg mailing list