hippietrail
hippietrail

Reputation: 16974

Idiomatic ES6/ESnext way to clone an object while replacing one item with another using a different key?

If I want to do a shallow clone of an object without mutating while replacing adding new items or replacing items with new items using the same key I know I can use Object.assign()

const oldOb = { foo:10, bar:20 };
const newOb = Object.assign({}, oldOb, { bar:100 });

But what about if I want to replace bar:20 with baz:50?

I know I can use delete ob[bar] but that's mutation, which I want to avoid.

Is there a neat functional programming way to achieve this with newer ES6/ES7/Babel features?

Upvotes: 2

Views: 293

Answers (1)

cyr_x
cyr_x

Reputation: 14257

As mentioned by @FelixKling in the comments, just using delete obj.key on an already cloned object would be the simplest solution and is perfectly fine regarding the concept of immutability.

But if you want a more "complex" solution you could use destructuring to clone the object and remove the desired property.

const l = console.log;

function remove(o, p) {
  const { [p]: undefined, ...props } = o;
  return props;
}

const obj = { someProp: 'someValue', originalProperty: 'originalValue' };

l('remove:\n', remove(obj, 'originalProperty'));
l('original object: \n', obj);

If you want to have a replace, rename and remove functionality all in one method, then you could go for this one:

const l = console.log;

function replace(o, p, n, v = o[p]) {
  const { [p]: undefined, ...props } = { ...o, ...(n ? { [n]: v } : {}) };
  return props;
}

const obj = { someProp: 'someValue', originalProperty: 'originalValue' };

l('replace:\n', replace(obj, 'originalProperty', 'replacedProperty', 'replacedValue'));
l('rename:\n', replace(obj, 'originalProperty', 'replacedProperty'));
l('remove:\n', replace(obj, 'originalProperty'));
l('original object:\n', obj);

A longer version for better understanding of the replace function:

function replace(
    obj,
    currentProperty,
    newProperty,
    newPropertyValue = obj[currentProperty]
  ) {
  let replacementObject = {};
  if(newProperty) {
    replacementObject = { [newProperty]: newPropertyValue };
  }
  const { [currentProperty]: undefined, ...remainingProperties } = Object.assign({}, obj, replacementObject);
  return remainingProperties;
}

Upvotes: 3

Related Questions