Łukasz
Łukasz

Reputation: 123

Is it possible for map to mutate object?

I have a very strange case which indicates that either map function mutates object or lodash incorrectly clones the object. This piece of code is just a sample: a function that takes an object as an argument and returns a copy of it using cloneDeep from lodash. Then I use this object to generate a chart.

const copyObject = data => {
  const copy = _.cloneDeep(data);

  const dataWithIndexes = copy.nodes.map((node, index) => {
    node.index = index;
    return node;
  });

  return copy;
};

export const copiedData = copyObject(sampleData);

Entry data in this case is an object with arrays of objects:

{
  nodes: [
    { name: "transactions.main", layer: 0 },
    ...
  ],
  links: [
    { source: 3, target: 3, value: 4 },
    ...
  ]
}

As you can see map inside function is not used at all and this is the point. When I am using original, unmodified object within my chart generate function it works fine, when I am copying the object with function shown above, it doesn't work, BUT when I comment this dataWithIndexes variable it starts working again. Is it possible in any way that map mutates the copied object? Or maybe it's lodash's fault? It may clone the object incorrectly, but on the other hand I only use the map on it, it doesn't modify it in any way.

Maybe anyone can help me solving this riddle T_T

Thanks

Upvotes: 4

Views: 435

Answers (1)

Amardeep Bhowmick
Amardeep Bhowmick

Reputation: 16908

You are modifying the node object parameter in the map(...) callback by overwriting its index property: node.index = index. This way the original object in the array is getting mutated although it returns a new array.

This would still happen even though you are not using the dataWithIndexes that is because the map(...) is still run and when it does it mutates the objects in the copy.node array with the new values of the index in the callback.

To avoid it, make a copy of the node object parameter in the map call and assign the new index there and then return it from the callback:

const dataWithIndexes = copy.nodes.map((node, index) => {
    return {...node, index};
});

Upvotes: 3

Related Questions