You can use Array.prototype.reduceRight, like this
var keys = ['a', 'b', 'c'];
var value = 'hello';
console.log(keys.reduceRight(function (pastResult, currentKey) {
var obj = {};
obj[currentKey] = pastResult;
return obj;
}, value));
// { a: { b: { c: 'hello' } } }
reduceRight will process the array from the right to left. And everytime we create a new object and store the old object against the current key name. So, as we iterate one by one, we are increasing the nesting of objects. We pass value as the last parameter, which will be used as the pastResult the very first time.
If you want to fix your original code, you just have to stop assigning new objects to data and use another variable, like this
var keys = ['a', 'b', 'c'],
value = 'hello',
data = {},
temp = data;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (i < keys.length - 1) {
if (temp[key] === undefined) {
temp[key] = {};
}
} else {
temp[key] = value;
}
temp = temp[key];
}
console.log(data)
// { a: { b: { c: 'hello' } } }
Even this can be written succinctly, like this
for (var i = 0; i < keys.length - 1; i++) {
temp = (temp[keys[i]] = {});
}
temp[keys[keys.length - 1]] = value;
We iterate all the keys except the last one and assign a new object to the current key every time and since we assign it back to temp, on the next iteration temp will refer the newly created object. And finally, we assign the value to the last element of keys.