Episode 1 — Fundamentals / 1.24 — Object Methods

1.24.d — Object.fromEntries()

In one sentence: Object.fromEntries(iterable) converts an iterable of [key, value] pairs into a plain object — the inverse of Object.entries().

Navigation: <- 1.24.c — Object.freeze . 1.24.e — Object.is ->


1. What does Object.fromEntries() do?

It takes any iterable that yields [key, value] pairs and builds a plain object from them.

const entries = [["name", "Alice"], ["age", 30], ["role", "admin"]];
const obj = Object.fromEntries(entries);

console.log(obj);
// { name: "Alice", age: 30, role: "admin" }

Think of it as the reverse of Object.entries():

const original = { a: 1, b: 2, c: 3 };
const roundTrip = Object.fromEntries(Object.entries(original));

console.log(roundTrip);            // { a: 1, b: 2, c: 3 }
console.log(roundTrip === original); // false  -- new object

2. Syntax

Object.fromEntries(iterable)
ParameterDescription
iterableAny iterable whose elements are [key, value] pairs (arrays, Maps, generators, etc.)
ReturnsA new plain object

Throws TypeError if the argument is not iterable or if entries are not pair-like.


3. Accepts any iterable of [key, value] pairs

From a 2D array

const pairs = [["x", 10], ["y", 20]];
Object.fromEntries(pairs);
// { x: 10, y: 20 }

From a Map

Map is an iterable of [key, value] entries, so conversion is direct:

const map = new Map();
map.set("name", "Alice");
map.set("age", 30);
map.set("active", true);

const obj = Object.fromEntries(map);
console.log(obj);
// { name: "Alice", age: 30, active: true }

Note: Map keys that are not strings or symbols become string keys in the resulting object:

const map = new Map([[1, "one"], [2, "two"]]);
const obj = Object.fromEntries(map);
console.log(obj);      // { "1": "one", "2": "two" }
console.log(obj[1]);   // "one"  (key coerced to "1")

From a generator

function* generatePairs() {
  yield ["a", 1];
  yield ["b", 2];
  yield ["c", 3];
}

const obj = Object.fromEntries(generatePairs());
console.log(obj);  // { a: 1, b: 2, c: 3 }

4. The entries/fromEntries pipeline

The most powerful pattern: extract entries, transform with array methods, rebuild the object.

Object  -->  Object.entries()  -->  Array of [key, value]
                                        |
                                    .map() / .filter() / .reduce()
                                        |
Object  <--  Object.fromEntries()  <--  Transformed array

Filter properties by value

const scores = { alice: 85, bob: 42, charlie: 91, diana: 38 };

const passing = Object.fromEntries(
  Object.entries(scores).filter(([_, score]) => score >= 50)
);

console.log(passing);
// { alice: 85, charlie: 91 }

Transform values (apply discount)

const prices = { laptop: 1000, phone: 800, tablet: 500 };

const discounted = Object.fromEntries(
  Object.entries(prices).map(([item, price]) => [item, price * 0.9])
);

console.log(discounted);
// { laptop: 900, phone: 720, tablet: 450 }

Filter properties by key

const data = { name: "Alice", _id: "abc123", email: "a@b.com", _rev: "1" };

const publicFields = Object.fromEntries(
  Object.entries(data).filter(([key]) => !key.startsWith("_"))
);

console.log(publicFields);
// { name: "Alice", email: "a@b.com" }

Pick specific keys

function pick(obj, keys) {
  return Object.fromEntries(
    Object.entries(obj).filter(([key]) => keys.includes(key))
  );
}

const user = { name: "Alice", age: 30, role: "admin", email: "a@b.com" };
console.log(pick(user, ["name", "email"]));
// { name: "Alice", email: "a@b.com" }

Omit specific keys

function omit(obj, keys) {
  return Object.fromEntries(
    Object.entries(obj).filter(([key]) => !keys.includes(key))
  );
}

console.log(omit(user, ["role"]));
// { name: "Alice", age: 30, email: "a@b.com" }

5. Converting URLSearchParams

URLSearchParams is iterable and yields [key, value] pairs:

const searchString = "?search=hello+world&page=2&lang=en";
const params = new URLSearchParams(searchString);

const paramsObj = Object.fromEntries(params);
console.log(paramsObj);
// { search: "hello world", page: "2", lang: "en" }

Caveat: If a parameter appears multiple times, only the last value is kept:

const params = new URLSearchParams("color=red&color=blue");
const obj = Object.fromEntries(params);
console.log(obj);
// { color: "blue" }  -- "red" is lost!

For multi-value params, use params.getAll("color") instead.


6. Converting FormData

const form = document.querySelector("form");
const formData = new FormData(form);

// FormData is iterable of [key, value]
const data = Object.fromEntries(formData);
console.log(data);
// { username: "alice", password: "secret123", remember: "on" }

Same caveat about duplicate keys applies.


7. Duplicate keys

When the input contains duplicate keys, the last value wins:

const entries = [["a", 1], ["b", 2], ["a", 3]];
const obj = Object.fromEntries(entries);

console.log(obj);
// { a: 3, b: 2 }  -- first "a" (1) was overwritten by second "a" (3)

8. Swapping keys and values

const original = { a: "1", b: "2", c: "3" };

const swapped = Object.fromEntries(
  Object.entries(original).map(([key, value]) => [value, key])
);

console.log(swapped);
// { "1": "a", "2": "b", "3": "c" }

Warning: This only works cleanly when values are unique and suitable as keys.


9. Grouping and restructuring

Count occurrences

const words = ["apple", "banana", "apple", "cherry", "banana", "apple"];

const counts = Object.fromEntries(
  [...new Set(words)].map(word => [
    word,
    words.filter(w => w === word).length,
  ])
);

console.log(counts);
// { apple: 3, banana: 2, cherry: 1 }

Merge two arrays into an object

const keys = ["name", "age", "city"];
const values = ["Alice", 30, "NYC"];

const obj = Object.fromEntries(
  keys.map((key, i) => [key, values[i]])
);

console.log(obj);
// { name: "Alice", age: 30, city: "NYC" }

10. Relationship with Object.entries()

DirectionMethodInputOutput
Object -> PairsObject.entries(obj)ObjectArray<[string, any]>
Pairs -> ObjectObject.fromEntries(iterable)Iterable of [key, value]Object

They are inverses but not perfectly so:

const original = { a: 1, b: 2 };
const roundTrip = Object.fromEntries(Object.entries(original));

// roundTrip deeply equals original, but:
// - It is a NEW object (different reference)
// - Non-enumerable properties are lost
// - Symbol keys are lost
// - Prototype is always Object.prototype (even if original had a custom prototype)

11. Edge cases

// Empty iterable -> empty object
Object.fromEntries([]);            // {}
Object.fromEntries(new Map());     // {}

// Non-string keys are coerced to strings
Object.fromEntries([[1, "one"]]);   // { "1": "one" }
Object.fromEntries([[true, "yes"]]); // { "true": "yes" }

// Nested arrays with more than 2 elements -- extra elements ignored
Object.fromEntries([["a", 1, "extra"]]);  // { a: 1 }

// Not iterable -- throws
// Object.fromEntries(42);       // TypeError
// Object.fromEntries(null);     // TypeError

12. Browser support

Object.fromEntries was introduced in ES2019. It is supported in all modern browsers and Node.js 12+. For older environments, a polyfill is straightforward:

// Simple polyfill (for understanding, not production)
if (!Object.fromEntries) {
  Object.fromEntries = function (iterable) {
    const obj = {};
    for (const [key, value] of iterable) {
      obj[key] = value;
    }
    return obj;
  };
}

Key takeaways

  1. Object.fromEntries(iterable) builds an object from [key, value] pairs — the inverse of Object.entries().
  2. Accepts any iterable: arrays, Maps, generators, URLSearchParams, FormData.
  3. The entries -> transform -> fromEntries pipeline is the standard pattern for filtering/mapping object properties.
  4. Duplicate keys: last value wins.
  5. Useful utility functions like pick and omit are built on this pattern.

Explain-It Challenge

Explain without notes:

  1. What does Object.fromEntries([["x", 1], ["y", 2]]) return?
  2. Write a pipeline that takes an object and returns a new object with all values doubled (assuming numeric values).
  3. If a URLSearchParams has ?a=1&a=2, what does Object.fromEntries(params) produce? Why?

Navigation: <- 1.24.c — Object.freeze . 1.24.e — Object.is ->