Docs
10.7-Object-fromEntries-Advanced
10.7 Object.fromEntries and Advanced Object Methods
Overview
This section covers advanced Object static methods including Object.fromEntries(), Object.groupBy(), and other modern object manipulation techniques. These methods provide powerful ways to transform, group, and manipulate object data.
Learning Objectives
- •Convert iterables of key-value pairs to objects
- •Group array elements into objects
- •Transform objects using entries/fromEntries pattern
- •Apply advanced object manipulation patterns
Object.fromEntries()
Basic Usage
Object.fromEntries() transforms a list of key-value pairs into an object. It's the inverse of Object.entries().
// From array of pairs
const entries = [
['name', 'John'],
['age', 30],
['city', 'NYC'],
];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: 'John', age: 30, city: 'NYC' }
// From Map
const map = new Map([
['a', 1],
['b', 2],
['c', 3],
]);
const objFromMap = Object.fromEntries(map);
console.log(objFromMap); // { a: 1, b: 2, c: 3 }
entries() + fromEntries() Pattern
This powerful pattern allows functional transformations on objects:
const prices = { apple: 1.5, banana: 0.75, orange: 2.0 };
// Double all prices
const doubled = Object.fromEntries(
Object.entries(prices).map(([key, value]) => [key, value * 2])
);
console.log(doubled); // { apple: 3, banana: 1.5, orange: 4 }
// Filter properties
const expensive = Object.fromEntries(
Object.entries(prices).filter(([key, value]) => value > 1)
);
console.log(expensive); // { apple: 1.5, orange: 2 }
// Transform keys
const upperKeys = Object.fromEntries(
Object.entries(prices).map(([key, value]) => [key.toUpperCase(), value])
);
console.log(upperKeys); // { APPLE: 1.5, BANANA: 0.75, ORANGE: 2 }
Practical Examples
// Parse URL query string
function parseQueryString(qs) {
return Object.fromEntries(new URLSearchParams(qs));
}
const params = parseQueryString('name=John&age=30&city=NYC');
console.log(params); // { name: 'John', age: '30', city: 'NYC' }
// Swap keys and values
function swapKeysValues(obj) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [value, key])
);
}
const original = { a: 1, b: 2, c: 3 };
const swapped = swapKeysValues(original);
console.log(swapped); // { 1: 'a', 2: 'b', 3: 'c' }
// Merge multiple objects' entries
function mergeObjects(...objects) {
return Object.fromEntries(objects.flatMap((obj) => Object.entries(obj)));
}
Object.groupBy() (ES2024)
Basic Grouping
Object.groupBy() groups array elements by a key returned from a callback:
const people = [
{ name: 'Alice', age: 25, department: 'Engineering' },
{ name: 'Bob', age: 30, department: 'Marketing' },
{ name: 'Charlie', age: 25, department: 'Engineering' },
{ name: 'Diana', age: 30, department: 'Engineering' },
];
// Group by department
const byDepartment = Object.groupBy(people, (person) => person.department);
console.log(byDepartment);
// {
// Engineering: [{ name: 'Alice', ... }, { name: 'Charlie', ... }, { name: 'Diana', ... }],
// Marketing: [{ name: 'Bob', ... }]
// }
// Group by age
const byAge = Object.groupBy(people, (person) => person.age);
console.log(byAge);
// {
// 25: [{ name: 'Alice', ... }, { name: 'Charlie', ... }],
// 30: [{ name: 'Bob', ... }, { name: 'Diana', ... }]
// }
Custom Grouping Logic
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Group by even/odd
const byParity = Object.groupBy(numbers, (n) => (n % 2 === 0 ? 'even' : 'odd'));
console.log(byParity);
// { odd: [1, 3, 5, 7, 9], even: [2, 4, 6, 8, 10] }
// Group by range
const byRange = Object.groupBy(numbers, (n) => {
if (n <= 3) return 'low';
if (n <= 7) return 'medium';
return 'high';
});
console.log(byRange);
// { low: [1, 2, 3], medium: [4, 5, 6, 7], high: [8, 9, 10] }
Map.groupBy()
When you need Map keys (not just strings):
const items = [
{ type: 'fruit', name: 'apple' },
{ type: 'vegetable', name: 'carrot' },
{ type: 'fruit', name: 'banana' },
];
// Using complex objects as keys
const grouped = Map.groupBy(items, (item) => item.type);
console.log(grouped.get('fruit'));
// [{ type: 'fruit', name: 'apple' }, { type: 'fruit', name: 'banana' }]
Object.hasOwn() (ES2022)
A safer alternative to hasOwnProperty:
const obj = { name: 'John' };
// Old way (can be overwritten)
console.log(obj.hasOwnProperty('name')); // true
// New way (safer)
console.log(Object.hasOwn(obj, 'name')); // true
// Works with objects without prototype
const nullProto = Object.create(null);
nullProto.key = 'value';
// nullProto.hasOwnProperty('key'); // Error!
console.log(Object.hasOwn(nullProto, 'key')); // true
Advanced Patterns
Deep Object Transformation
function deepTransformKeys(obj, transformer) {
if (Array.isArray(obj)) {
return obj.map((item) => deepTransformKeys(item, transformer));
}
if (obj !== null && typeof obj === 'object') {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [
transformer(key),
deepTransformKeys(value, transformer),
])
);
}
return obj;
}
// Convert snake_case to camelCase
const snakeToCamel = (str) =>
str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
const apiResponse = {
user_name: 'john',
user_data: {
birth_date: '1990-01-01',
email_address: 'john@example.com',
},
};
const camelCased = deepTransformKeys(apiResponse, snakeToCamel);
console.log(camelCased);
// { userName: 'john', userData: { birthDate: '1990-01-01', emailAddress: 'john@example.com' } }
Object Picking and Omitting
function pick(obj, keys) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => keys.includes(key))
);
}
function omit(obj, keys) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => !keys.includes(key))
);
}
const user = {
id: 1,
name: 'John',
password: 'secret',
email: 'john@example.com',
};
console.log(pick(user, ['id', 'name'])); // { id: 1, name: 'John' }
console.log(omit(user, ['password'])); // { id: 1, name: 'John', email: 'john@example.com' }
Object Mapping
function mapValues(obj, fn) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key, fn(value, key)])
);
}
function mapKeys(obj, fn) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [fn(key, value), value])
);
}
const scores = { math: 85, english: 92, science: 78 };
console.log(mapValues(scores, (v) => v / 100)); // Convert to decimals
console.log(mapKeys(scores, (k) => k.toUpperCase())); // Uppercase keys
Invert Object
function invert(obj) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [String(value), key])
);
}
const statusCodes = { OK: 200, NotFound: 404, ServerError: 500 };
const codeToStatus = invert(statusCodes);
console.log(codeToStatus); // { '200': 'OK', '404': 'NotFound', '500': 'ServerError' }
Defaults/Merge Pattern
function defaults(target, ...sources) {
const allEntries = [target, ...sources].flatMap(Object.entries);
const merged = new Map();
// First value for each key wins
for (const [key, value] of allEntries) {
if (!merged.has(key)) {
merged.set(key, value);
}
}
return Object.fromEntries(merged);
}
const options = { timeout: 5000 };
const defaultOptions = { timeout: 3000, retries: 3, cache: true };
console.log(defaults(options, defaultOptions));
// { timeout: 5000, retries: 3, cache: true }
Polyfills
Object.groupBy Polyfill
if (!Object.groupBy) {
Object.groupBy = function (array, callback) {
return array.reduce((groups, item, index) => {
const key = callback(item, index);
(groups[key] ??= []).push(item);
return groups;
}, {});
};
}
Object.hasOwn Polyfill
if (!Object.hasOwn) {
Object.hasOwn = function (obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
};
}
Summary
| Method | Purpose | Example |
|---|---|---|
Object.fromEntries() | Create object from entries | Object.fromEntries([['a',1]]) → {a:1} |
Object.groupBy() | Group array by key | Object.groupBy(arr, fn) |
Object.hasOwn() | Safe hasOwnProperty | Object.hasOwn(obj, 'key') |
| entries + fromEntries | Transform objects | Filter, map, transform |