Array.prototype.toObjectByProperty( element=>element.property )

Naveen Chawla naveen.chwl at gmail.com
Mon Aug 7 21:41:03 UTC 2017


Hi Darien!

Very interesting!

Set.entries() is interesting - it has [value, value] with the justification
(according to MDN) "to keep the API similar to the Map object".

Array entries() - it's really unclear why this would ever be used, do you
have any idea?

Object entries() is another strange case. Iterating over Object.keys with
key=> leaves myObject[key] to access the value, whereas iterating over
Object.entries with entry=> requires entry[0] and entry[1] which seems more
verbose for access, and less readable! So do you know why this was
introduced?

All seem motivated by Map. And I think the pattern is unhealthy, for the
reasons given before.

Sometimes we need to look at how code looks out there in production, to
appreciate the benefits of a language feature. Imagine the mapping of an
array passed into a function (or a reduce), repeated in code for several
arrays that need caching for quick access - obviously you would expect that
to be factored out into a `toObjectByProperty` function in code, right?
That's what I'm talking about. Now imagine that transition function offered
by iterable - an extra dependency useful across multiple projects is gone.
It's only nice. Isn't it?

On Tue, 8 Aug 2017 at 02:26 Darien Valentine <valentinium at gmail.com> wrote:

> > The concept of using a 2-element array to represent a key and value is
> unique to Maps
>
> The entries pattern is not unique to `Map` — it’s also used by
> `Object.entries`, `Set.entries`, and `Array.entries` — e.g.
>
>     for (const [ index, member ] of array.entries()) ...
>
> A bit tangential, but in the case of `Map`, it’s perhaps notable that the
> contract for "entry" is not "an array of two and only two members". It is
> "any object at all", with the implied expectation that you’d want
> properties keyed by "0" and "1" defined on it in order for it to be useful.
>
> Regardless of one’s thoughts on `Map` (which I use quite a bit
> personally), the "entries" pattern is well established in ES. (I’d also
> point out that adding a method for composition from entries does not
> preclude supporting other approaches.)
>
> On Mon, Aug 7, 2017 at 4:54 PM, Darien Valentine <valentinium at gmail.com>
> wrote:
>
>> Sorry, meant to reply on-list there!
>>
>> On Mon, Aug 7, 2017 at 4:54 PM, Darien Valentine <valentinium at gmail.com>
>> wrote:
>>
>>> > The concept of using a 2-element array to represent a key and value
>>> is unique to Maps
>>>
>>> The entries pattern is not unique to `Map` — it’s also used by
>>> `Object.entries`, `Set.entries`, and `Array.entries` — e.g.
>>>
>>>     for (const [ index, member ] of array.entries()) ...
>>>
>>> A bit tangential, but in the case of `Map`, it’s perhaps notable that
>>> the contract for "entry" is not "an array of two and only two members". It
>>> is "any object at all", with the implied expectation that you’d want
>>> properties keyed by "0" and "1" defined on it in order for it to be useful.
>>>
>>> Regardless of one’s thoughts on `Map` (which I use quite a bit
>>> personally), the "entries" pattern is well established in ES.
>>>
>>>
>>>
>>> On Mon, Aug 7, 2017 at 3:24 PM, Naveen Chawla <naveen.chwl at gmail.com>
>>> wrote:
>>>
>>>> Hi Darien!
>>>>
>>>> The concept of using a 2-element array to represent a key and value is
>>>> unique to Maps and if I'm not mistaken, exists purely because there wasn't
>>>> a tight, compact alternative that could house a key and value where the key
>>>> could be an object.
>>>>
>>>> However, if we are going straight from iterable to Object, I don't
>>>> think we should be propagating the "[key, value] as an array" pattern. It's
>>>> unclean partly because it's 2 elements max and IDEs can't inherently show
>>>> warnings if you accidentally added more, unless it has some intelligence
>>>> about the method itself. Partly also because the arrays are not immediately
>>>> readable unless you already know the that the arrays mean [key, value].
>>>>
>>>> I'm not convinced that Maps have any real value at all right now vs
>>>> objects (despite what the documentation says): currently they only offer
>>>> the ability to have objects as keys but without custom key equality (only
>>>> ===), and you lose the elegant square bracket syntax for accessing
>>>> elements, among other things, so it's unclear to me how compelling the use
>>>> of Maps vs objects is at all in real world scenarios, so I'm not sure
>>>> anything about Maps should be a pattern for other language features.
>>>>
>>>> Iterables are very generic, since they can include generators, sets
>>>> etc. Objects are a fundamental construct, so it makes sense to be able to
>>>> cleanly transition between these structures.
>>>>
>>>> Adding the idea to iterable in general (instead of just Array) would
>>>> look like e.g.:
>>>>
>>>> ```
>>>> const cache = iterable.toObjectByProperty(item=>item.id)
>>>> ```
>>>>
>>>> On Sun, 6 Aug 2017 at 02:12 Darien Valentine <valentinium at gmail.com>
>>>> wrote:
>>>>
>>>>> FWIW, while I find needs like this common, too, where Map is sensible
>>>>> instead of
>>>>> Object, it does come out pretty clean:
>>>>>
>>>>> ```
>>>>> const a = [
>>>>>   {id: "tjc", name: "T.J. Crowder"},
>>>>>   {id: "nc", name: "Naveen Chawla"},
>>>>>   {id: "lh", name: "Lachlan Hunt"}
>>>>> ];
>>>>>
>>>>> const index = new Map(a.map(member => [ member.name, member ]));
>>>>> ```
>>>>>
>>>>> Although I’m also puzzled by the suggestion that reducing to an object
>>>>> is an abuse,
>>>>> I do find I wish there were a complement to `Object.entries`:
>>>>>
>>>>> ```
>>>>> // Object to pairs, and therefore map, is simple:
>>>>>
>>>>> const map = new Map(Object.entries(obj));
>>>>>
>>>>> // Converting back is also simple ... but not exactly expressive:
>>>>>
>>>>> [ ...map ].reduce((acc, [ key, val ]) => Object.assign(acc, { [key]:
>>>>> val }));
>>>>> ```
>>>>>
>>>>> Something like `Object.fromEntries` would not provide as much sugar
>>>>> for the
>>>>> OP case as `toObjectByProperty`, but it gets pretty close and has the
>>>>> advantage
>>>>> of being more generic; `toObjectByProperty` strikes me as rather
>>>>> specific for a
>>>>> built-in, especially since one might want to map by a derived value
>>>>> rather than
>>>>> a property. Both map<->object and array<->object cases would become
>>>>> more
>>>>> expressive — plus it follows pretty naturally from the existence of
>>>>> `Object.entries` that there might be a reverse op.
>>>>>
>>>>> ```
>>>>> Object.fromEntries(a.map(a.map(member => [ member.name, member ])));
>>>>> ```
>>>>>
>>>>> In other words, `Object.fromEntries(Object.entries(obj))` would be
>>>>> equivalent in
>>>>> effect to `Object.assign({}, obj)`.
>>>>>
>>>>> Would that adequately address this case you think? My sense is that
>>>>> it’s better to supply generic helpers before more specific helpers when it
>>>>> comes to built-ins.
>>>>> _______________________________________________
>>>>> es-discuss mailing list
>>>>> es-discuss at mozilla.org
>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>
>>>>
>>>
>>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170807/9af89382/attachment-0001.html>


More information about the es-discuss mailing list