tag - Cómo establecer la propiedad del objeto(de la propiedad del objeto de...) dado su nombre de cadena en JavaScript?
title of page html (10)
Supongamos que solo nos dan
var obj = {};
var propName = "foo.bar.foobar";
¿Cómo podemos establecer la propiedad obj.foo.bar.foobar
a un cierto valor (por ejemplo, "hello world")? Así que quiero lograr esto, mientras que solo tenemos el nombre de la propiedad en una cadena:
obj.foo.bar.foobar = "hello world";
Una muy simple.
Sin recurrencias ni devoluciones de llamadas por sobrecarga.
function setDeepVal(obj, path, val) {
var props = path.split(''.'');
for (var i = 0, n = props.length - 1; i < n; ++i) {
obj = obj[props[i]] = obj[props[i]] || {};
}
obj[props[i]] = val;
return obj;
}
// TEST
var obj = { hello : ''world'' };
setDeepVal(obj, ''foo.bar.baz'', 1);
setDeepVal(obj, ''foo.bar2.baz2'', 2);
console.log(obj);
Aquí hay una función get y set que acabo de compilar a partir de un par de hilos + algún código personalizado.
También creará claves que no existen en el conjunto.
function setValue(object, path, value) {
var a = path.split(''.'');
var o = object;
for (var i = 0; i < a.length - 1; i++) {
var n = a[i];
if (n in o) {
o = o[n];
} else {
o[n] = {};
o = o[n];
}
}
o[a[a.length - 1]] = value;
}
function getValue(object, path) {
var o = object;
path = path.replace(//[(/w+)/]/g, ''.$1'');
path = path.replace(/^/./, '''');
var a = path.split(''.'');
while (a.length) {
var n = a.shift();
if (n in o) {
o = o[n];
} else {
return;
}
}
return o;
}
Aquí hay una función simple para hacer eso usando referencia.
function setValueByPath (obj, path, value) {
var ref = obj;
path.split(''.'').forEach(function (key, index, arr) {
ref = ref[key] = index === arr.length - 1 ? value : {};
});
return obj;
}
Aquí hay uno que devuelve el objeto actualizado
function deepUpdate(value, path, tree, branch = tree) {
const last = path.length === 1;
branch[path[0]] = last ? value : branch[path[0]];
return last ? tree : deepUpdate(value, path.slice(1), tree, branch[path[0]]);
}
const path = ''cat.dog'';
const updated = deepUpdate(''a'', path.split(''.''), {cat: {dog: null}})
// => { cat: {dog: ''a''} }
Dado que esta pregunta parece responderse con respuestas incorrectas, solo me referiré a la respuesta correcta de una pregunta similar
function setDeepValue(obj, value, path) {
if (typeof path === "string") {
var path = path.split(''.'');
}
if(path.length > 1){
var p=path.shift();
if(obj[p]==null || typeof obj[p]!== ''object''){
obj[p] = {};
}
setDeepValue(obj[p], value, path);
}else{
obj[path[0]] = value;
}
}
Utilizar:
var obj = {};
setDeepValue(obj, ''Hello World'', ''foo.bar.foobar'');
Puede dividir la ruta y verificar si el siguiente elemento existe. Si no asigna un objeto a la nueva propiedad.
Devuelve luego el valor de la propiedad.
Al final asigna el valor.
function setValue(object, path, value) {
var fullPath = path.split(''.''),
way = fullPath.slice(),
last = way.pop();
way.reduce(function (r, a) {
return r[a] = r[a] || {};
}, object)[last] = value;
}
var object = {},
propName = ''foo.bar.foobar'',
value = ''hello world'';
setValue(object, propName, value);
console.log(object);
Todas las soluciones sobrepasaban cualquiera de los datos originales cuando se configuraba, así que modifiqué con lo siguiente, también lo convertí en un solo objeto:
var obj = {}
nestObject.set(obj, "a.b", "foo");
nestObject.get(obj, "a.b"); // returns foo
var nestedObject = {
set: function(obj, propString, value) {
var propNames = propString.split(''.''),
propLength = propNames.length-1,
tmpObj = obj;
for (var i = 0; i <= propLength ; i++) {
if (i === propLength){
if(tmpObj[propNames[i]]){
tmpObj[propNames[i]] = value;
}else{
tmpObj[propNames[i]] = value;
}
}else{
if(tmpObj[propNames[i]]){
tmpObj = tmpObj[propNames[i]];
}else{
tmpObj = tmpObj[propNames[i]] = {};
}
}
}
return obj;
},
get: function(obj, propString){
var propNames = propString.split(''.''),
propLength = propNames.length-1,
tmpObj = obj;
for (var i = 0; i <= propLength ; i++) {
if(tmpObj[propNames[i]]){
tmpObj = tmpObj[propNames[i]];
}else{
break;
}
}
return tmpObj;
}
};
También puede cambiar las funciones para que sean un método Oject.prototype cambiando obj param por esto:
Object.prototype = { setNested = function(){ ... }, getNested = function(){ ... } }
{}.setNested(''a.c'',''foo'')
editar: he creado un testcase jsPerf.com para comparar la respuesta aceptada con mi versión. Resulta que mi versión es más rápida, especialmente cuando vas muy profundo.
var nestedObjectAssignmentFor = function(obj, propString, value) {
var propNames = propString.split(''.''),
propLength = propNames.length-1,
tmpObj = obj;
for (var i = 0; i <= propLength ; i++) {
tmpObj = tmpObj[propNames[i]] = i !== propLength ? {} : value;
}
return obj;
}
var obj = nestedObjectAssignment({},"foo.bar.foobar","hello world");
1.
1.
function assign(obj, prop, value) {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e] =
Object.prototype.toString.call(obj[e]) === "[object Object]"
? obj[e]
: {},
prop,
value);
} else
obj[prop[0]] = value;
}
var obj = {},
propName = "foo.bar.foobar";
assign(obj, propName, "Value");