I am looking for a nice solution to access a property by string value, but if the property does not exist it should create it. If the root structure already has defined some parts of the structure, the attributes should not be overwritten, but merged instead.
For example if you have an empty object
test
test = {}
test.foo.name = "Hallo" // <<- foo is an Object
test.foo[3] = "Test" // <<- foo should remain as Object, not as Array
test.foo.data[3].bar = 100 // <<- should not overwrite test.foo.name
Object.setValue = function(node, flatKey, value) {
flatKey = flatKey.replace("[", ".");
flatKey = flatKey.replace("]", "");
var parts = flatKey.split(".")
var oldNode = node
parts.forEach(function(key, index) {
if (/^\+?(0|[1-9]\d*)$/.test(key)) {
key = key * 1
if (index > 0) {
var oldValue = parts[index - 1]
if (!Array.isArray(oldNode[oldValue])) {
oldNode[oldValue] = []
node = oldNode[oldValue]
}
}
}
if (node[key] == undefined) {
node[key] = {}
}
oldNode = node
node = node[key]
}); // for each
oldNode[parts[parts.length - 1]] = value
return oldNode[parts[parts.length - 1]]
} // function
var test = {}
Object.setValue(test, "foo.name", "Mr. Foo")
Object.setValue(test, "foo.data[0].bar", 100)
Object.setValue(test, "and.another[2].deep", 20)
console.log("test = " + JSON.stringify(test))
console.log("test.foo.data[0].bar = " + test.foo.data[0].bar)
You could split the path and reduce the path by walking the given object. If no Object exist, create a new property with the name, or an array. Later assign the value.
function setValue(object, path, value) {
var way = path.replace(/\[/g, '.').replace(/\]/g, '').split('.'),
last = way.pop();
way.reduce(function (o, k, i, kk) {
return o[k] = o[k] || (isFinite(i + 1 in kk ? kk[i + 1] : last) ? [] : {});
}, object)[last] = value;
}
var test = {};
setValue(test, "foo.name", "Mr. Foo");
setValue(test, "foo.data[0].bar", 100);
setValue(test, "and.another[2].deep", 20);
console.log(test);