Quiero escribir una función que tome keyName , newValue y object , y devuelva el objeto con el par clave/valor actualizado. Por ejemplo...
Dados estos datos:
const data = { token: { id: "abcxyz", year: "2022" }, order_data: { customer: "Jane", shipping: { country: "US", state: "TX" } } }y una función con estos argumentos:
const updateObject = (keyName, newValue, object) => { ... }Quiero poder llamar:
const newObject = updateObject("customer", "Bob", data);de modo que
newObject = { token: { id: "abcxyz", year: "2022" }, order_data: { customer: "Bob", shipping: { country: "US", state: "TX" } } }Mi intento incorrecto actual se ve así:
const updateObject = (keyName, newVal, object) => { const results = {}; for (var key in object) { if (key === keyName) { results = { ...object, keyName: newVal }; } else { results[key] = object[key]; if (typeof object[key] === "object") { updateObject(keyName, newVal, object.key); } } } return results };He estado investigando publicaciones sobre operadores de recursión y propagación todo el día, pero no puedo hacerlo bien. El objeto anidado puede tener cualquier forma y profundidad que me esté desconcertando.
La sintaxis extendida en su función no es necesaria (ya crea un nuevo objeto con results = {} ), y keyname crea una propiedad .keyname que no tiene un nombre dinámico (el mismo problema al usar object.key en lugar de object[key] - es posible que desee volver a visitar la notación de punto frente a paréntesis ). Pero el problema principal es que su función updateObject no actualiza el object que se pasó, sino que devuelve uno nuevo, y debe tenerlo en cuenta en su llamada recursiva. asi que deberia ser
function updateObject(keyName, newVal, object) { const results = {}; for (var key in object) { if (key === keyName) { results[key] = newVal; } else if (typeof object[key] === "object" && object[key] !== null) { results[key] = updateObject(keyName, newVal, object[key]); } else { results[key] = object[key]; } } return results; }Es bastante simple. Simplemente recorremos y encontramos la clave y luego actualizamos el valor. si no se encuentra, llamamos a la función de nuevo. Lo más importante es devolver el valor actualizado al final de la función.
Esta línea var newData = JSON.parse(JSON.stringify(data)); es solo para que no editemos el objeto original como usted solicitó
var data = { token: { id: "abcxyz", year: "2022" }, order_data: { customer: "Bob", shipping: { country: "US", state: "TX" } } } const updateObject = (keyName, newVal, object) => { for (var key in object) { if (key === keyName) { object[key] = newVal; } else { if(typeof object[key] === "object"){ object[key] = updateObject(keyName, newVal, object[key]); } } } return object; }; var newData = JSON.parse(JSON.stringify(data)); updateObject("customer", "Test", newData); console.log(data); console.log(newData);Si está buscando un enfoque que no mute su original (y ahora, ¿quién no lo estaría? 😀) podemos hacerlo dividiendo nuestro objeto en entradas asignándolas al nuevo valor si las claves coinciden y son recurrentes. en ellos de lo contrario, luego volviendo a juntar los resultados. La recursividad se detiene cuando se pasa un no objeto, simplemente devolviéndolo sin modificar.
Se parece a esto:
const updateObject = (keyName, newValue, object) => Object (object) === object ? Object .fromEntries (Object .entries (object) .map ( ([k, v]) => [k, k == keyName ? newValue : updateObject (keyName, newValue, v)] )) : object const data = {token: {id: "abcxyz", year: "2022"}, order_data: {customer: "Jane", shipping: {country: "US", state: "TX"}}} console .log ('Before:', data) console .log ('customer = "Bob":', updateObject ('customer', 'Bob', data)) console .log ('state = "NY":', updateObject('state', 'NY', data)) console .log ('After (original data non mutatued):', data) .as-console-wrapper {max-height: 100% !important; top: 0}Sin embargo, tenga en cuenta que existe una preocupación real, independientemente de cómo se implemente, que podría haber claves con nombres similares en diferentes partes de los datos, y que cualquier técnica actualizaría las incorrectas. Puede buscar herramientas que establezcan esto por ruta, con algo como
setPath (['order_data', 'customer'], 'Bob', data)o quizás
setPath ('order_data.address.state', 'NY', data)