Object.fromEntries TC39 proposal for Object.fromEntries ( https://github.com/tc39/proposal-object-from-entries )

Proposal

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 }

Rationale

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 Maps 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.

When is this useful ?

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.

Motivating examples

Object-to-object property transformations

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 }

Object from existing collection

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 ]));

Prior art

Lodash

Underscore and Lodash provide a _.fromPairs function which constructs an object from a list of key-value pairs.

Python

In Python, a dict can be initialized with an array of key-value tuples:

dict([('two', 2), ('one', 1), ('three', 3)])

Object.fromEntries ( https://css-tricks.com/all-the-new-es2019-tips-and-tricks/ )

In ES2017, we were introduced to Object.entries .

This was a function that translated an object into its array representation. Something like this:

let students = {
  amelia: 20,
  beatrice: 22,
  cece: 20,
  deirdre: 19,
  eloise: 21
}

Object.entries(students)
// [
//  [ 'amelia', 20 ],
//  [ 'beatrice', 22 ],
//  [ 'cece', 20 ],
//  [ 'deirdre', 19 ],
//  [ 'eloise', 21 ]
// ]

This was a wonderful addition because it allowed objects to make use of the numerous functions built into the Array prototype.

Things like map, filter, reduce, etc.

Unfortunately, it required a somewhat manual process to turn that result back into an object.

let students = {
  amelia: 20,
  beatrice: 22,
  cece: 20,
  deirdre: 19,
  eloise: 21
}

// convert to array in order to make use of .filter() function
let overTwentyOne = Object.entries(students).filter(([name, age]) => {
  return age >= 21
}) // [ [ 'beatrice', 22 ], [ 'eloise', 21 ] ]

// turn multidimensional array back into an object
let DrinkingAgeStudents = {}
for (let [name, age] of overTwentyOne) {
    DrinkingAgeStudents[name] = age;
}
// { beatrice: 22, eloise: 21 }

Object.fromEntries is designed to remove that loop! It gives you much more concise code that invites you to make use of array prototype methods on objects.

let students = {
  amelia: 20,
  beatrice: 22,
  cece: 20,
  deirdre: 19,
  eloise: 21
}

// convert to array in order to make use of .filter() function
let overTwentyOne = Object.entries(students).filter(([name, age]) => {
  return age >= 21
}) // [ [ 'beatrice', 22 ], [ 'eloise', 21 ] ]

// turn multidimensional array back into an object
let DrinkingAgeStudents = Object.fromEntries(overTwentyOne);
// { beatrice: 22, eloise: 21 }

It is important to note that arrays and objects are different data structures for a reason.

There are certain cases in which switching between the two will cause data loss.

The example below of array elements that become duplicate object keys is one of them.

let students = [
  [ 'amelia', 22 ],
  [ 'beatrice', 22 ],
  [ 'eloise', 21],
  [ 'beatrice', 20 ]
]

let studentObj = Object.fromEntries(students);
// { amelia: 22, beatrice: 20, eloise: 21 }
// dropped first beatrice!

Articles

https://javascript.info