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 ofObject.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)
| Parameter | Description |
|---|---|
iterable | Any iterable whose elements are [key, value] pairs (arrays, Maps, generators, etc.) |
| Returns | A 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()
| Direction | Method | Input | Output |
|---|---|---|---|
| Object -> Pairs | Object.entries(obj) | Object | Array<[string, any]> |
| Pairs -> Object | Object.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
Object.fromEntries(iterable)builds an object from[key, value]pairs — the inverse ofObject.entries().- Accepts any iterable: arrays, Maps, generators, URLSearchParams, FormData.
- The entries -> transform -> fromEntries pipeline is the standard pattern for filtering/mapping object properties.
- Duplicate keys: last value wins.
- Useful utility functions like
pickandomitare built on this pattern.
Explain-It Challenge
Explain without notes:
- What does
Object.fromEntries([["x", 1], ["y", 2]])return? - Write a pipeline that takes an object and returns a new object with all values doubled (assuming numeric values).
- If a URLSearchParams has
?a=1&a=2, what doesObject.fromEntries(params)produce? Why?
Navigation: <- 1.24.c — Object.freeze . 1.24.e — Object.is ->