don't prefer Object over Map #33
Description
I suggest renaming groupBy
and groupByToMap
to groupByToObject
and groupBy
respectively or dropping support for an object altogether.
-
there are various reasons to prefer
Map
overObject
reasons from MDN
Map Object Accidental Keys A Map
does not contain any keys by default. It only contains what is explicitly put into it.An
Object
has a prototype, so it contains default keys that could collide with your own keys if you're not careful.Note: As of ES5, this can be bypassed by using {{jsxref("Object.create", "Object.create(null)")}}, but this is seldom done.
Key Types A Map
's keys can be any value (including functions, objects, or any primitive).The keys of an Object
must be either a {{jsxref("String")}} or a {{jsxref("Symbol")}}.Key Order The keys in
Map
are ordered in a simple, straightforward way: AMap
object iterates entries, keys, and values in the order of entry insertion.Although the keys of an ordinary
Object
are ordered now, this was not always the case, and the order is complex. As a result, it's best not to rely on property order.The order was first defined for own properties only in ECMAScript 2015; ECMAScript 2020 defines order for inherited properties as well. See the OrdinaryOwnPropertyKeys and EnumerateObjectProperties abstract specification operations. But note that no single mechanism iterates all of an object's properties; the various mechanisms each include different subsets of properties. ({{jsxref("Statements/for...in", "for-in")}} includes only enumerable string-keyed properties; {{jsxref("Object.keys")}} includes only own, enumerable, string-keyed properties; {{jsxref("Object.getOwnPropertyNames")}} includes own, string-keyed properties even if non-enumerable; {{jsxref("Object.getOwnPropertySymbols")}} does the same for just
Symbol
-keyed properties, etc.)Size
The number of items in a Map
is easily retrieved from its {{jsxref("Map.prototype.size", "size")}} property.The number of items in an Object
must be determined manually.Iteration A Map
is an iterable, so it can be directly iterated.Object
does not implement an iteration protocol, and so objects are not directly iterable using the JavaScript for...of statement (by default).Note:
-
An object can implement the iteration protocol, or you can get
an iterable for an object using
Object.keys
orObject.entries
. - The for...in statement allows you to iterate over the enumerable properties of an object.
Performance Performs better in scenarios involving frequent additions and removals of key-value pairs.
Not optimized for frequent additions and removals of key-value pairs.
-
An object can implement the iteration protocol, or you can get
an iterable for an object using
-
destructuring and transformation for JSON stringification can be accomplished from a
Map
easily enough usingObject.fromEntries
:const { even, odd } = Object.fromEntries( array.groupBy((num, index, array) => { return num % 2 === 0 ? "even" : "odd"; }) );
-
groupBy
(to a null-prototype object) may set a precedence for future features to avoid defaulting to more proper keyed collections likeMap
andSet
and use objects and arrays instead; these have been used historically and continue to be used prevalently (from what I can tell) even when there are now these more optimized/appropriate collections available
in short, making it easy for developers to use a Map
seems like a win to me and paves the way for more rich data structures and utilities using them and for those use cases where an Object
is wanted (destructuring and JSON stringification) then there is a built-in way to quickly, efficiently, and (IMO) ergonomically transform the returned Map
to an Object
. If further convenience/ergonomics is desired then a groupByToObject
method could still be provided while the shorter go-to method groupBy
would return a Map
as the "preferred" type to work with