Docs

README

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

MethodPurposeExample
Object.fromEntries()Create object from entriesObject.fromEntries([['a',1]]){a:1}
Object.groupBy()Group array by keyObject.groupBy(arr, fn)
Object.hasOwn()Safe hasOwnPropertyObject.hasOwn(obj, 'key')
entries + fromEntriesTransform objectsFilter, map, transform

Resources

README - JavaScript Tutorial | DeepML