Generic iteration method idea with example implementation and tests

Renki Ivanko fatalis.erratum at gmail.com
Mon May 9 02:54:55 UTC 2016


ES5 added the Array iteration methods for iterating over, transforming and
reducing arrays, which arguably offer benefits in readability and
description of intent, but there are certain pitfalls with applying the
methods to the other collection types, which have increased in ES6 with the
addition of new types like Map and Set. I've made a table as illustration
with the different methods of looping or iterating over objects and the
minimum 'plumbing' required: https://goo.gl/71dQsG

It's apparent that the `for..of` loop syntax is the most uniform approach
to traversing collections, while trying to use the `Array` iteration
methods requires additional steps and, in the case of iterable objects,
requires transforming them to arrays, which loses the benefits of the lazy
iteration. Usage of the `for..of` loops also varies depending on whether
entries (key-value pairs) or values are used. A solution would be to offer
the familiar semantics of the ES5 `Array` iteration methods that would
support the existing collection types, and also allow defining support for
new types. I've made an example implementation of this idea:
https://github.com/slikts/esnext-generic-iteration/blob/master/src/iteration.js
(the other files in the repository implement reconstructing object types,
polyfilling native support and a basic test suite).

The implementation works by adding two new `Symbol` properties to the
iterable objects: `@@shape` and `@@reconstruct`. Shape can be one of the
values of `@@shape.indexed` or `@@shape.entries`. The generic iteration
methods use the shape properties to normalize the return values of the
iterators, allowing the same signatures for methods and callbacks to be
used for all the various types. The `@@reconstruct` property returns a
method that returns a reconstructor object that has a method for accepting
a value and an optional key, and a property with the resulting collection,
whose type is based on the `@@species` property of the constructor. This
allows for the same behavior as with subclassed native arrays, where the
output of the iteration methods will be constructed based on the
`@@species` property. If the iterable object does not support the
reconstructor protocol, the result is an `Array` object.

Some code examples:

```
map([1, 2], x => x + 1) // -> [2, 3]

filter('abc', x => x !== 'b') // -> ['a', 'c']

map(new Map([['a', 1], ['b', 2]], (v, k) => v + k) // Map { 'a' => '1a',
'b' => '2b' }
```

The method and callback signatures in this implementation match those of
the Array iteration methods.

An argument for the desirability of generic iterator methods is the
inclusion of similar methods in utility libraries like lodash that deal
with collections.

Additional thought: this approach makes it very simple to define an
iterable object like has previously been proposed with `Dict`.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160509/8cb969df/attachment.html>


More information about the es-discuss mailing list