dinamicas - Acceder o crear objetos JavaScript anidados con la clave de cadena sin eval
recorrer array de objetos javascript (2)
Estoy buscando una buena solución para acceder a una propiedad por valor de cadena, pero si la propiedad no existe, debería crearla. Si la estructura raíz ya ha definido algunas partes de la estructura, los atributos no se deben sobrescribir, sino que deben fusionarse.
Por ejemplo, si tiene una test
objeto vacía y desea establecer una estructura profunda sin usar eval. p.ej
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
He escrito una solución que realmente funciona, pero es un código bastante malo, supongo:
También disponible como jsfiddle: https://jsfiddle.net/gvaLzqqf/4/
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)
Sin embargo, ¿hay alguna forma mejor de lograr esto?
No reinventaría la rueda en este caso, y en cambio usaría lodash . Específicamente la función set () . Según su ejemplo:
var object = { ''a'': [{ ''b'': { ''c'': 3 } }] };
_.set(object, ''a[0].b.c'', 4);
console.log(object.a[0].b.c);
// => 4
_.set(object, [''x'', ''0'', ''y'', ''z''], 5);
console.log(object.x[0].y.z);
// => 5
Podrías dividir el camino y reducir el camino caminando el objeto dado. Si no existe ningún objeto, cree una nueva propiedad con el nombre o una matriz. Más tarde asigne el valor.
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);