Usage:
set(obj, 'a.b.c.d.e', value)
||set(obj, [a, 'b', '@#$', 'd', 'e'], [1, 2, 3])
||set(arr, '0.1.2', true)
- For bracket notation (e.g. obj['@#$']), use arrays
- Creates arrays with numbered keys (numbers not allowed as objects keys, see other revisions for that)
Explanation
function set (
obj, // object in which to set nested properties
path, // path of properties, as string or array
value // value to set
) {
return
(path.split && path.split('.') || path) // if split exists, is a string (array of properties). Else, is array and ready to go
.reduce( // reduce is handy to loop through each property, setting and retrieving them
(o, k, i, a) => ( // "o" is the current nested property (object/array), "k" is the next property to set
return
(o || obj)[k] || // in first loop, "o" is nothing, so use obj. If property k exists already, get it
((o || obj)[k] = // else set it
(i==a.length-1) ? value : // if is the last property in the chain, its the one to set it
(isNaN(a[i+1])? {} : [])) // else we need to set next step in chain. If next property is a number, this should be an array, else an object
, 0) // inicial "o" value, not really that important - could be anything
}