Re: Non-constructible constructors and Arrays

On 7/28/11, Jonas Sicking <jonas@sicking.cc> wrote:
> On Thu, Jul 28, 2011 at 7:12 PM, Allen Wirfs-Brock
> <allen@wirfs-brock.com> wrote:
>>
>> On Jul 28, 2011, at 5:04 PM, Jonas Sicking wrote:
>>
>>> As I asked above, what would the mutating functions do to "live"
>>> NodeList? And IMHO only APIs that want to return "live" objects should
>>> return NodeLists. Others should simply return arrays.
>>>
>>>
>>
>> In ES5 all of the Array.prototype functions are defined to operate upon
>> generic objects with "array indexed" (ie, integer string values)
>> properties. The objects they operate upon do not need to be Array
>> instances. The functions are specified in terms of the basic ES5 internal
>> operations such as [[Get]], [[Put]],  etc.  Such generic objects (or even
>> Array instances for that matter) may, in ES5, have non-writable and
>> non-deletable properties and the objects may be non-extensible.  For that
>> reason, the array algorithms all explicitly define how to deal with such
>> situations.  Generally, they throw when they try to modify a property in a
>> manner that is forbidden for that object.
>>
>> If a DOM implementation provides reasonable implementations of [[Get]],
>> [[Put]] and friends then the Array functions should just work on its DOM
>> objects. Trying to reverse a read-only DOM object may not do anything
>> useful, but its unuseful behavior would still be fully specified.
>
Yeah.

> I'm very aware how the Array functions are defined. The problem is
> that there aren't any reasonable defaults we could provide for
> NodeList's [[Put]] operations simply due to what a NodeList
> represents.
>
Well you could do like this: For [[Put]](I, N), if `I` is between 0
and nodeList.length, call replaceChild. If `I` == nodeList.length,
call appendChild, otherwise, `I` is out of range so throw a
RangeError. That makes NodeList work like an array. It's easier to let
programs  use an Array instead.

I don't know if this is Alex' gripe but to me, NodeList -> Array (do
operation) -> NodeList results in inelegant code. Alex proposes to
make NodeList become an array but there's another way to improve the
situation.

I remember suggesting before a method
`element.setChildNodes(nodeArray)`. I think this is the direction to
go in; so using arrays to replaceChildNodes(nodeArray),
appendChildNodes(nodeArray), insertChildNodes(ref, nodeArray),
removeChildren(). A nodeArray coud be either a NodeList or an Array,
but if any property < length is not a node, a TypeError would be
thrown.

That would make a lot of things a lot easier. Like sorting lists, for
example, it would be used as:

var kids = ul.children;
arraySort(kids, byLastName);
ul.replaceChildNodes(kids);

Or for the one line wonderers:
ul.replaceChildNodes(arraySort(ul.children, byLastName));

Otherwise you have to remove childNodes and then use a loop to append
them in order.

> The only reasonable thing we could do is to make all mutating
> operations throw, which frankly would be a pretty strange API. I.e.
> all NodeLists would have whole host of operations like .push and
> .shift which always would throw. It would seem much better if those
> operations weren't there.
>
Making mutable nodelist would be weird. Using an Array there makes sense.
-- 
Garrett

Received on Friday, 29 July 2011 03:24:27 UTC