Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looking for function identical to lodash's [_.set]()

I'm looking for a function identical to lodash's _.set except it should return a new object without modifying the original. Are there any implementations of this?

Right now I'm deep-cloning and then setting:

let data = _.cloneDeep(this.state.data);
_.set(data, name, value);
this.setState({data})

But I don't think it's necessary to do a full deep clone, we'd just need to do a shallow clone of the object at the deepest level, no?

e.g.

let oldData = { 'a': [{ 'b': { 'c': 3 }, 'd': {'e': 4} }] };
let newDate = withValue(oldData, 'a[0].b.c', 5);

The proposed withValue function would perform a shallow clone of a, a[0] and a[0].b and then modify the new a[0].b.c to 5. We would not need to make a copy of a[0].d.

like image 881
mpen Avatar asked May 01 '16 21:05

mpen


2 Answers

This is going to be a multi-part answer.

Immutable set:

As you're using lodash, you can use the FP version of lodash and use .set (or .setWith to be able to supply an object path) which will do an immutable update.

Or, as this looks like a React codebase you can use the $set helper of React.

Or you can just use the Spread Operator:

const newObj = {...oldObj, prop: newValue }

Or Object.assign:

const newObj = Object.assign({}, oldObj, { prop: newValue });

Performance:

As you're mentioning performance (and not just deeply cloning an object) you might want to look in to an immutable framework. The more developed codebases increase performance by different measures. E.g. here's what immutable.js says:

These data structures are highly efficient on modern JavaScript VMs by using structural sharing via hash maps tries and vector tries

...and Mori says:

Efficient immutable data structures - no cloning required [...] Modern JavaScript engines like V8, JavaScriptCore, and SpiderMonkey deliver the performance needed to implement persistent data structures well.

like image 113
Emil Oberg Avatar answered Nov 12 '22 17:11

Emil Oberg


lodash/fp as Emil suggested should work.

Example:

const setIn = require('lodash/fp/set');
this.setState({data: setIn(name, value, this.state.data)});

N.B. the argument order is different than regular lodash.

like image 35
mpen Avatar answered Nov 12 '22 16:11

mpen