I have been using a version of the function below to create and/or add values to nested objects:
function assign(obj, keyPath, value) {
const lastKeyIndex = keyPath.length-1;
for (let i = 0; i < lastKeyIndex; ++ i) {
const key = keyPath[i];
if (!(key in obj)){
obj[key] = {}
}
obj = obj[key];
}
obj[keyPath[lastKeyIndex]] = value;
}
(Posted in 2011 by kennytm, slightly modified above: Javascript: how to dynamically create nested objects using object names given by an array).
Example usage to specify a value in which the keys represent the (0) database name, (1) table name, (3) id value, and (4) column name:
let obj = {}
assign(obj, ['farm', 'products', '25', 'product_name'], 'lettuce');
console.log(JSON.stringify(obj));
/* (reformatted)
{
"farm": {
"products": {
"25": {
"product_name":"lettuce"
}
}
}
}
*/
We can add a second value for the same row:
assign(obj, ['farm', 'products', '25', 'product_unit'], 'head');
console.log(JSON.stringify(obj));
/* (reformatted)
{
"farm": {
"products": {
"25": {
"product_name":"lettuce",
"product_unit":"head"
}
}
}
}
*/
Or additional values from different rows, tables, and databases:
assign(obj, ['farm', 'equipment', '17', 'equipment_name'], 'tractor');
console.log(JSON.stringify(obj));
/* (reformatted)
{
"farm": {
"products": {
"25": {
"product_name": "lettuce",
"product_unit": "head"
}
},
"equipment": {
"17": {
"equipment_name": "tractor"
}
}
}
}
*/
The function works perfectly but I can't figure out how it manages to aggregate the key path. It would appear to simply create or replace an existing object with an object consisting of only the last key and the value. In fact, if I execute the same statements not inside a function and without using a loop, the statements do exactly that.
(Starting with assignment of the first value to an empty object):
let obj = {}
let key;
// first iteration of the function's loop
key = 'farm';
if (!(key in obj)) {
obj[key] = {}
}
obj = obj[key];
// second iteration
key = 'products';
if (!(key in obj)) {
obj[key] = {}
}
obj = obj[key];
// third iteration
key = '25';
if (!(key in obj)) {
obj[key] = {}
}
obj = obj[key];
// final line from the function
obj['product name'] = 'lettuce';
console.log(JSON.stringify(obj));
// {"product name":"lettuce"}
As you can see, the object is not nested but simply replaced at each step.
What magic makes the function work differently?