Add denseProxy, various collection.js improvements
This commit is a bit messy, but splitting it out seems difficult. More
to come with regards to testing the remainder of `collection.js`.
Originally, there were plans for both `denseProxy` and a
`revocableDenseProxy`, but the latter is of unclear utility (this is
hardly the use·case that revocable proxies are designed for), so it was
removed.
`concat`, `filter`, and `toArray` now always return an array instead of
respecting `.constructor[Symbol.species]`. `toArray` now supports
sparse arrays (if the argument is a sparse arraylike object, or if an
iterator does not produce a value when it yields); there is now also a
`toDenseArray` with behaviour more similar to `Array.from`.
Awkwardly, `toArray` won¦t preserve sparseness when called with an
existing sparse array, since the `.[Symbol.iterator]` method of arrays
yields a value of `undefined` for missing keys. And supporting a
semantic distinction between iterator results with a `.value` of
`undefined` and those with no `.value` present is definitely a grey
area of the Ecmascript specification. So the following changes may be
called for :—
- Disallowing sparseness when calling `toArray` with an iterable,
because “sparse iterables” is not a weldefined concept, and
- When calling `toArray` with a “collection” (as ♓🌟 Piscēs has
them), prioritizing iterating over its indices rather than treating
it as an iterable.
It is an open question whether objects which are neither iterables nor
collections (i·e, that don¦t respond to `.[Symbol.iterator]`, are not
concat‐spreadable, or which do not have a valid length) should be
supported in `toArray` and kin at all.
(It is probably worth renaming “collection” to “indexed collection” at
some point.)
The “finding” methods are now `findFirstIndex`, `findFirstEntry`, and
`findFirstItem` (and there are corresponding `findLast—` versions).
These differ from the built·in methods in that they return `undefined`,
not `-1`, if a match is not found.