javascript

examples

examples.js
/**
 * 10.7 Object.fromEntries and Advanced Object Methods - Examples
 */

// ============================================
// OBJECT.FROMENTRIES() BASICS
// ============================================

console.log('=== Object.fromEntries Basics ===');

// From array of pairs
const entries = [
  ['name', 'John'],
  ['age', 30],
  ['city', 'NYC'],
];

const obj = Object.fromEntries(entries);
console.log('From entries:', obj);

// From Map
const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3],
]);

const objFromMap = Object.fromEntries(map);
console.log('From Map:', objFromMap);

// Roundtrip: entries -> fromEntries
const original = { x: 10, y: 20, z: 30 };
const roundtrip = Object.fromEntries(Object.entries(original));
console.log('Roundtrip:', roundtrip);

// ============================================
// TRANSFORM PATTERN
// ============================================

console.log('\n=== Transform Pattern ===');

const prices = { apple: 1.5, banana: 0.75, orange: 2.0, mango: 3.5 };

// Double all prices
const doubled = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, value * 2])
);
console.log('Doubled:', doubled);

// Apply discount
const discounted = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, +(value * 0.9).toFixed(2)])
);
console.log('10% off:', discounted);

// Filter expensive items
const expensive = Object.fromEntries(
  Object.entries(prices).filter(([, value]) => value > 1)
);
console.log('Expensive (>$1):', expensive);

// Transform keys to uppercase
const upperKeys = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key.toUpperCase(), value])
);
console.log('Upper keys:', upperKeys);

// ============================================
// URL QUERY STRING PARSING
// ============================================

console.log('\n=== URL Query String ===');

function parseQueryString(qs) {
  return Object.fromEntries(new URLSearchParams(qs));
}

const params = parseQueryString('name=John&age=30&city=New+York&active=true');
console.log('Parsed params:', params);

// Build query string from object
function toQueryString(obj) {
  return new URLSearchParams(Object.entries(obj)).toString();
}

console.log('To query:', toQueryString({ search: 'hello', page: 2 }));

// ============================================
// SWAP KEYS AND VALUES
// ============================================

console.log('\n=== Swap Keys/Values ===');

function swapKeysValues(obj) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [value, key])
  );
}

const colorCodes = { red: '#FF0000', green: '#00FF00', blue: '#0000FF' };
const codesToColors = swapKeysValues(colorCodes);
console.log('Swapped:', codesToColors);

// ============================================
// OBJECT.GROUPBY() (ES2024)
// ============================================

console.log('\n=== Object.groupBy ===');

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' },
  { name: 'Eve', age: 35, department: 'Marketing' },
];

// Check if Object.groupBy exists (ES2024)
if (typeof Object.groupBy === 'function') {
  // Group by department
  const byDepartment = Object.groupBy(people, (p) => p.department);
  console.log('By department:', byDepartment);

  // Group by age
  const byAge = Object.groupBy(people, (p) => p.age);
  console.log('By age:', byAge);
} else {
  // Polyfill/manual implementation
  function groupBy(array, keyFn) {
    return array.reduce((groups, item) => {
      const key = keyFn(item);
      (groups[key] ??= []).push(item);
      return groups;
    }, {});
  }

  const byDepartment = groupBy(people, (p) => p.department);
  console.log('By department (polyfill):', byDepartment);
}

// ============================================
// CUSTOM GROUPING LOGIC
// ============================================

console.log('\n=== Custom Grouping ===');

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Polyfill for environments without Object.groupBy
const groupBy = (arr, fn) =>
  arr.reduce((acc, item) => {
    const key = fn(item);
    (acc[key] ??= []).push(item);
    return acc;
  }, {});

// Group by even/odd
const byParity = groupBy(numbers, (n) => (n % 2 === 0 ? 'even' : 'odd'));
console.log('By parity:', byParity);

// Group by range
const byRange = groupBy(numbers, (n) => {
  if (n <= 3) return 'low';
  if (n <= 7) return 'medium';
  return 'high';
});
console.log('By range:', byRange);

// Group strings by first letter
const words = ['apple', 'banana', 'apricot', 'blueberry', 'cherry', 'avocado'];
const byFirstLetter = groupBy(words, (w) => w[0].toUpperCase());
console.log('By first letter:', byFirstLetter);

// ============================================
// OBJECT.HASOWN()
// ============================================

console.log('\n=== Object.hasOwn ===');

const user = { name: 'John', age: 30 };

// Compare approaches
console.log('hasOwnProperty:', user.hasOwnProperty('name')); // true
console.log('Object.hasOwn:', Object.hasOwn(user, 'name')); // true

// Object.hasOwn is safer with null prototype objects
const nullProtoObj = Object.create(null);
nullProtoObj.key = 'value';

// nullProtoObj.hasOwnProperty('key');  // Would throw!
console.log('hasOwn on null proto:', Object.hasOwn(nullProtoObj, 'key')); // true

// Inherited vs own
const child = Object.create({ inherited: true });
child.own = 'value';

console.log('own property:', Object.hasOwn(child, 'own')); // true
console.log('inherited:', Object.hasOwn(child, 'inherited')); // false

// ============================================
// PICK AND OMIT UTILITIES
// ============================================

console.log('\n=== Pick and Omit ===');

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 fullUser = {
  id: 1,
  name: 'John',
  email: 'john@example.com',
  password: 'secret123',
  role: 'admin',
};

console.log('Pick:', pick(fullUser, ['id', 'name', 'email']));
console.log('Omit:', omit(fullUser, ['password']));

// ============================================
// MAP VALUES AND KEYS
// ============================================

console.log('\n=== Map Values/Keys ===');

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(
  'To percent:',
  mapValues(scores, (v) => v + '%')
);
console.log(
  'To decimals:',
  mapValues(scores, (v) => v / 100)
);
console.log(
  'Upper keys:',
  mapKeys(scores, (k) => k.toUpperCase())
);
console.log(
  'Prefix keys:',
  mapKeys(scores, (k) => 'score_' + k)
);

// ============================================
// DEEP TRANSFORM KEYS
// ============================================

console.log('\n=== Deep Transform Keys ===');

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;
}

// Snake case to camel case
const snakeToCamel = (str) =>
  str.replace(/_([a-z])/g, (_, c) => c.toUpperCase());

// Camel case to snake case
const camelToSnake = (str) =>
  str.replace(/[A-Z]/g, (c) => '_' + c.toLowerCase());

const apiResponse = {
  user_name: 'john_doe',
  user_data: {
    birth_date: '1990-01-01',
    email_address: 'john@example.com',
    phone_numbers: [{ phone_type: 'home', phone_number: '123-456-7890' }],
  },
};

const camelCased = deepTransformKeys(apiResponse, snakeToCamel);
console.log('Camel cased:', JSON.stringify(camelCased, null, 2));

// ============================================
// DEFAULTS MERGE
// ============================================

console.log('\n=== Defaults Merge ===');

function defaults(target, ...sources) {
  const allEntries = [target, ...sources].flatMap(Object.entries);
  const merged = new Map();

  for (const [key, value] of allEntries) {
    if (!merged.has(key)) {
      merged.set(key, value);
    }
  }

  return Object.fromEntries(merged);
}

const options = { timeout: 5000 };
const defaults1 = { timeout: 3000, retries: 3 };
const defaults2 = { retries: 5, cache: true };

console.log('Merged defaults:', defaults(options, defaults1, defaults2));

// ============================================
// INVERT OBJECT
// ============================================

console.log('\n=== Invert Object ===');

function invert(obj) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [String(value), key])
  );
}

const statusCodes = {
  OK: 200,
  Created: 201,
  NotFound: 404,
  ServerError: 500,
};

console.log('Inverted:', invert(statusCodes));

// ============================================
// PRACTICAL: CONFIGURATION MERGE
// ============================================

console.log('\n=== Configuration Merge ===');

function mergeConfig(defaultConfig, ...overrides) {
  const entries = [defaultConfig, ...overrides].flatMap((obj) =>
    Object.entries(obj)
  );

  const result = {};
  for (const [key, value] of entries) {
    if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
      result[key] = { ...result[key], ...value };
    } else {
      result[key] = value;
    }
  }

  return result;
}

const defaultConfig = {
  port: 3000,
  database: { host: 'localhost', port: 5432 },
  logging: true,
};

const envConfig = {
  port: 8080,
  database: { port: 5433 },
};

console.log('Merged config:', mergeConfig(defaultConfig, envConfig));

// ============================================
// PRACTICAL: OBJECT DIFF
// ============================================

console.log('\n=== Object Diff ===');

function objectDiff(obj1, obj2) {
  const keys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
  const diff = { added: {}, removed: {}, changed: {} };

  for (const key of keys) {
    if (!(key in obj1)) {
      diff.added[key] = obj2[key];
    } else if (!(key in obj2)) {
      diff.removed[key] = obj1[key];
    } else if (obj1[key] !== obj2[key]) {
      diff.changed[key] = { from: obj1[key], to: obj2[key] };
    }
  }

  return diff;
}

const before = { a: 1, b: 2, c: 3 };
const after = { a: 1, b: 5, d: 4 };

console.log('Diff:', objectDiff(before, after));

console.log('\n=== Examples Complete ===');
Examples - JavaScript Tutorial | DeepML