Le 24/04/2010 22:50, J Z a écrit :
On Fri, Apr 23, 2010 at 10:30 PM, David Bruant <bru...@enseirb-matmeca.fr <mailto:bru...@enseirb-matmeca.fr>> wrote:

    Hi,

    In the HTML5 "status of this document" section, one can read :
    "This specification is intended to replace (be the new version of)
    what was previously the [...] DOM2 HTML specifications."
    This spec can be found here : http://www.w3.org/TR/DOM-Level-2-HTML/

    It defines ECMAScript language Binding
    (http://www.w3.org/TR/DOM-Level-2-HTML/ecma-script-binding.html).
    This document explains how to implement the DOM HTML interfaces in
    an ECMAScript-compliant environment.

    Because HTML5 is intended to replace DOM2 HTML, it can "freely"
    change ECMAScript bindings. My suggestion is the following :
    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.

    Would the WHATWG have the power to decide something similar
    regarding NodeList ?

    Any thoughts ?

    Thanks,

    David


As far as I can see, liveness of HTMLCollection actually does matter. When iterating over HTMLCollection, it's more or less a rule of thumb to "save" length, to avoid any kind of mismatch (in case code within loop modifies document and so affects length of collection in question):

for (var i = 0, length = collection.length; i < length; i++)
// instead of:
for (var i = 0; i < collection.length; i++)
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.



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
});
This code doesn't work as expected as the following doesn't either :
var divs = document.getElementsByTagName('div');
for(var i=0, l = divs.length ; i < l ; i++){
var el = divs[i]; // Due to the live-ness, this might not work as expected
    el.parentNode.removeChild(el);
}

This code written as a for-loop behave exactly the same way (in this case) as the .forEach one, so it's as buggy as the forEach one. My point is that forEach doesn't create more bugs than before, which is what you seem to imply. Adding .forEach and other Array extras wouldn't prevent programmers to remember that they are dealing with a live object even within a .forEach, the same way they are not supposed to forget it with a for-loop.

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


This has nothing to do with this thread, but document.getElementsByTagName('div') should return a NodeList (http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-A6C9094). Returning an HTMLCollection is a Firefox bug (https://bugzilla.mozilla.org/show_bug.cgi?id=14869).



// turning live collection into static array fixes this

Array.slice(document.getElementsByTagName('div')).forEach(function(el) {
  el.parentNode.removeChild(el);
});
I have not found anything about a Array.slice method and the ES5 .splice method doesn't seem to by usable in the way you describe. What did you mean ?

The idea of turning the live object into a static array seems to be an interesting one for some cases, but once again a problem you could solve with a for-loop (in a live object or not like the results of querySelectorAll) can be solved with a .forEach. On the other side, the equivalent for-loop (according to the ES5 spec) of a buggy forEach will be buggy as well.

David

Reply via email to