Re: What type should .findAll return

As a web developer, having DOM methods which return "real arrays" so we no
longer have to call `toArray(nodeList)` or `[].slice.call(nodeList)` would
be awesome.

On Fri, Nov 11, 2011 at 9:05 AM, Jonas Sicking <jonas@sicking.cc> wrote:

> Hi All,
>
> So, we've debated a lot the exact syntax for .find/.findAll. However I
> intentionally requested that we split out the discussions about return
> type for .findAll to a separate thread. So I'm starting that thread
> here.
>
> There are a few goals for the return'ed object that I've envisioned
> based on discussions so far:
>
> 1. It should have at least all of the non-mutating Array methods on
> it. Possibly the mutating methods too if we allow the returned object
> to be mutable.
> 2. It should have a object on the prototype chain where we can insert
> functions that are specifically useful for lists of nodes. Examples
> include .find/.findAll/.matchesSelector/.remove/.addEventListener
> 3. It would be good if it had the Array prototype object on it's
> prototype chain so that if Array.prototype was extended, it would
> affect this object too.
> 4. The object will *not* be live since live results from selector
> matching is slow.
>
> Since the returned object won't be live, I don't see a reason to make
> it immutable. Hence it seems like we could put Array.prototype on the
> prototype chain which would immediately make all non-mutating as well
> as mutating functions available on the object.
>
> We should also insert a new prototype object in the prototype chain.
> Hence we end up with something like:
>
> object -> [some type].prototype -> Array.prototype -> Object.prototype.
>
> And to ensure that the object acts as much as possible as an array it
> should also have it's [[Class]] set to that of an array. This has
> subtle effects on a number of functions. For example it affects what
> Object.toString() and Array.isArray returns, it affects how
> Array.concat behaves, and it affects the JSON serializer.
>
> I'm not sure if setting the [[Class]] to that of an array also gives
> the object the magical .length property, but if it doesn't, we need to
> also define that the returned object has such a property. Note that
> for Arrays, .length doesn't live on the prototype chain, but is rather
> a special property on the object itself.
>
> In other words, the returned object is exactly what you'd get if you did:
>
> a = new Array;
> a.__proto__ = [some type].prototype;
> [some type].prototype.__proto__ = Array.prototype;
>
> and then filled a with the set of nodes which matched the selector
> passed to .findAll.
>
>
> So the remaining question is, what should we use for [some type]. One
> option is to use NodeList. However this would result in NodeLists
> having Array.prototype on it's prototype chain. Including all mutating
> functions. This is iffy in general since NodeLists are returned from
> several APIs which return objects which represent a live result of a
> query. For example .getElementsByTagName, .getElementsByClassName and
> .childNodes.
>

Not to mention, that there must be a ton of code out there that assumes a
nodeList is not an array (mediocre feature detection code).


>
> An additional source of iffiness with this idea is that several of the
> mutating methods on Array.prototype don't throw if called on a
> immutable objects. For example .pop, .shift, .sort and .reverse all
> would not throw if called on an empty immutable list.
>
> Hence I propose that we add a new type. I don't care much for naming
> things so I'll just suggest NodeArray for now and let others fight it
> out over the name.
>
> For now we can leave NodeArray as empty and just let it be an
> extension point for page authors. We can discuss separately if
> .findAll/.matchesSelector should be added to NodeArray, and if so how
> they should behave.
>
> However, we should probably use NodeArray to "fix" one of the problems
> with some of the functions on Array.prototype. For example
> Array.prototype.filter always returns a new Array object. This would
> mean that:
>
> elem.findAll(...).filter(function(node) { ... });
>
> will return a plain Array and not a NodeArray. However we could make
> NodeArray override all such functions and keep their behavior
> identical except that they return NodeArrays.
>
> Another way to fix this problem would be to change the definition of
> Array.prototype.filter, but I have no idea if that's doable, or how
> that would be done.
>

That would involve hackling with es-discuss. I send an email to their
mailing list
https://mail.mozilla.org/pipermail/es-discuss/2011-November/018242.html


>
> What do people think?
>

overall it's a great idea. It is however a shame we duplicate functionality
with querySelectorAll


>
> / Jonas
>
>

Received on Friday, 11 November 2011 14:12:51 UTC