This repository is now archived, since the proposal is stage 4.
A proposal for a new static method Object.fromEntries
in ECMAScript for transforming a list of key-value pairs into an object.
This proposal was originally written by Darien Maillet Valentine and is being championed by Jordan Harband and Kevin Gibbons.
Object.fromEntries
is proposed to perform the reverse of Object.entries
: it accepts an iterable of key-value pairs and returns a new object whose own keys and corresponding values are given by those pairs.
obj = Object.fromEntries([['a', 0], ['b', 1]]); // { a: 0, b: 1 }
See DETAILS.md for details.
It's common to transform data held in various structures (arrays, maps, etc) from one form to another. When the data structures in question are both iterable this is typically simple:
map = new Map().set('foo', true).set('bar', false);
arr = Array.from(map);
set = new Set(map.values());
The iterable entries of a Map
take the form of key-value pairs. This dovetails nicely with the pairs returned by Object.entries
, such that you can convert objects to Map
s fairly expressively:
obj = { foo: true, bar: false };
map = new Map(Object.entries(obj));
However there is no inverse of Object.entries
for constructing objects from key-value pairs, so to do so one typically must write a helper or inline reducer:
obj = Array.from(map).reduce((acc, [ key, val ]) => Object.assign(acc, { [key]: val }), {});
This can be written many different ways, and potentially adds noise because it's not likely to be obviously related to the outward purpose of the function doing it.
Object.fromEntries
doesn’t imply a preference for ordinary objects over Map
.
If you have a collection with an arbitrary set of keys, even if they’re strings,
and especially if you intend to add/remove members over time, Map
data is
likely a more appropriate model than object properties. Properties are
well-suited to describing interfaces or fixed-shape models, but poorly suited
for modeling arbitrary hashes, and Map
aims to serve that case better.
We don’t always get to choose the model. This is one of the things fromEntries
is meant to help with. Recognizing that some data is an arbitrary collection,
one might prefer to model it using Map
. Later that data may need to be passed
to an API whose contract expects it to be modeled as an ordinary object though
(think query params, headers, etc): externalAPI(Object.fromEntries(myMap))
.
Data that comes from or must be serializable to JSON often uses properties to
model arbitrary collections. Metaprogramming that reflects on entries is another
scenario where we may manipulate or filter entries and then wish to convert them
back into an object — for example, when processing objects suitable for passing
to Object.defineProperties
. For one more example, while not everybody agrees
on whether it’s a good idea, contracts involving arbitrary-key objects may also
be chosen deliberately if an author feels they improve API ergonomics.
This allows the easy use of familiar array manipulation methods to transform objects:
obj = { abc: 1, def: 2, ghij: 3 };
res = Object.fromEntries(
Object.entries(obj)
.filter(([ key, val ]) => key.length === 3)
.map(([ key, val ]) => [ key, val * 2 ])
);
// res is { 'abc': 2, 'def': 4 }
A string-keyed Map
can be converted to an object, just as an object can already be converted to a Map
:
map = new Map([ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]);
obj = Object.fromEntries(map);
// compare existing functionality: new Map(Object.entries(obj))
This transformation may be simple for other Map
-like objects as well:
query = Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'));
For other collections, intermediate transformations can put the collection in the required form:
arr = [ { name: 'Alice', age: 40 }, { name: 'Bob', age: 36 } ];
obj = Object.fromEntries(arr.map(({ name, age }) => [ name, age ]));
Underscore and Lodash provide a _.fromPairs
function which constructs an object from a list of key-value pairs.
In Python, a dict
can be initialized with an array of key-value tuples:
dict([('two', 2), ('one', 1), ('three', 3)])