-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possibility to update a nested object's property in a non-mutable way #2948
Comments
Yes, I agree it would make sense to have a import _, { extend, isObject } from 'underscore';
var arrayIndex = /^\d+$/;
function keyValue(key, value) {
var result = {};
result[key] = value;
return result;
}
function innerSet(obj, path, value) {
if (!path.length) return value;
var key = path[0];
// Important: the next line prevents prototype pollution.
if (key === '__proto__') throw new Error('Prototype assignment attempted');
obj = obj || (arrayIndex.test(key) ? [] : {});
value = innerSet(obj[key], path.slice(1), value);
return extend(obj, keyValue(key, value));
}
function set(collection, path, value) {
if (!isObject(collection)) return collection;
path = _.toPath(path);
return innerSet(collection, path, value);
} Use it like this: set(foo, ['bar', 'baz', 'qux', 'quux', 'aNewProperty'], 'yay!'); You can add it to Underscore so you can also use it in chaining: import { mixin } from 'underscore';
import { set } from './your/own/module.js';
_.mixin({set});
_.chain({a: 1})
.extend({b: 2})
.set(['c', 0, 'd'], 3)
.value();
// {a: 1, b: 2, c: [{d: 3}]} If you want to use shorthand dotted paths of the form
Lodash is a fork of Underscore. Underscore is being actively maintained, so sticking with Underscore is fine. |
I just noticed the "non-mutable" part of the issue title... sorry for missing that previously. I want to avoid introducing new functions to Underscore that have the same name as a function in Lodash, but different semantics. So a import { clone } from 'underscore';
function innerSetClone(obj, path, value) {
if (!path.length) return value;
var key = path[0];
// Important: the next line prevents prototype pollution.
if (key === '__proto__') throw new Error('Prototype assignment attempted');
obj = obj || (arrayIndex.test(key) ? [] : {});
value = innerSetClone(obj[key], path.slice(1), value);
return extend(clone(obj), keyValue(key, value));
}
function setClone(collection, path, value) {
if (!isObject(collection)) return collection;
path = _.toPath(path);
return innerSetClone(collection, path, value);
} It does exactly the same thing as |
Currently I am using something like:
To make the point clear, it would be ideal to have something similar to the set method in lodash:
Note: I am not aware of how lodash and underscore are related but the current project I'm working on is using underscore. And at this time it's not possible to convert to lodash just for this single use-case.
The text was updated successfully, but these errors were encountered: