I want to write a function that takes a keyName
, newValue
, and object
, and returns the object with the updated key/value pair. For example...
Given this data:
const data = {
token: {
id: "abcxyz",
year: "2022"
},
order_data: {
customer: "Jane",
shipping: {
country: "US",
state: "TX"
}
}
}
and a function with these arguments:
const updateObject = (keyName, newValue, object) => {
...
}
I want to be able to call:
const newObject = updateObject("customer", "Bob", data);
so that
newObject = {
token: {
id: "abcxyz",
year: "2022"
},
order_data: {
customer: "Bob",
shipping: {
country: "US",
state: "TX"
}
}
}
My current wrong attempt looks like this:
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
};
I've been digging through posts on recursion and spread operators all day but can't quite get it right. The nested object can be any shape and depth which is throwing me off.
CodePudding user response:
The spread syntax in your function isn't necessary (you already create a new object with results = {}
), and keyname
creates a .keyname
property not one with a dynamic name (same problem in using object.key
instead of object[key]
- you might want to revisit dot vs bracket notation). But the main problem is that your updateObject
function doesn't update the object
it was passed, rather it returns a new one - and you need to consider that in your recursive call. So it should be
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;
}
CodePudding user response:
Its pretty simple. We just loop through and find the key and then update the value. if its not found we call the function again. Most important is to return the updated value at the end of the function
This line var newData = JSON.parse(JSON.stringify(data));
is just so that we dont edit the original object as you requested
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);
CodePudding user response:
Here's an approach using mutation. We essentially make a new object in a wrapper function, and recurse until we find the property and change its value, then return the new object.
let data = {
token: {
id: 'abcxyz',
year: '2022',
},
order_data: {
customer: 'Bob',
shipping: {
country: 'US',
state: 'TX',
},
},
};
function updateObject(key, newValue, obj) {
let newObj = Object.assign({}, obj); // Make new object
function updateKey(key, newValue, obj) {
if (typeof obj !== 'object') return; // Basecase
if (obj[key]) obj[key] = newValue; // Look for and edit property
else
for (let prop in obj) {
updateKey(key, newValue, obj[prop]); // Go deeper
}
}
updateKey(key, newValue, newObj);
return newObj;
}
console.log(updateObject('state', 'NY', data));
console.log(updateObject('customer', 'John', data));
console.log(updateObject('year', 2020, data));