I have the following code to get a key for a given object. So for the object {"hello": {"data": {"a": "world", "b": "random"}}}
if the key passed in was hello.data.a
, the output would be world
.
(object, key) => {
const keyParts = key.split(".");
let returnValue = object;
keyParts.forEach((part) => {
if (returnValue) {
returnValue = returnValue[part];
}
});
return returnValue;
}
I'm trying to figure out how I can delete a property dynamically in the same fashion. So for example for the same object and key, it would mutate the object to be {"hello": {"data": {"b": "random"}}}
.
Basically I want the same behavior as delete object.hello.data.a
. But the problem is the hello.data.a
part is a dynamic string passed in. Of course something like delete object[key]
wouldn't work since the key has nested levels. It would work if it is only 1 level deep, but wouldn't work for nested items.
One other important note is that performance is extremely important in this case. So although creating a new object and copying over all the properties except for the one I want to delete might work, but I have severe concerns of the performance impact of that vs the delete
keyword.
Due to other external factors I also do not want to set the property value to null
or undefined
. I want the key to actually be removed from the object.
How can I achieve this?
To delete, .pop()
off the last key to identify the property to remove. If you want to avoid the delete
keyword, you'll also want to replace the last object on which that key is on, rather than mutate it, so .pop()
off the next last key as well.
Then, use your current method (or .reduce
) to access the last outer object. To delete one of its keys:
delete
, using the saved key, use delete[nextLastKey][lastKey]
lastKey
during the creation of a new one, then assign the new object to the nextLastKey
of the parent object:const fn = (object, key) => {
const keys = key.split(".");
const lastKey = keys.pop();
const nextLastKey = keys.pop();
const nextLastObj = keys.reduce((a, key) => a[key], object);
// delete version:
// delete nextLastObj[nextLastKey][lastKey]
// non-delete version:
const { [lastKey]: _, ...rest } = nextLastObj[nextLastKey];
nextLastObj[nextLastKey] = rest;
return object;
}
const obj = {"hello": {"data": {"a": "world", "b": "random"}}};
const result = fn(obj, 'hello.data.a');
console.log(result);
Actually your answer is right there - in the code snippet that you provided. It just needs a little modification, like so:
const delProp = (object, key) => {
const keyParts = key.split(".");
let returnValue = object;
let parent, lastKey; // added
keyParts.forEach((part) => {
if (returnValue) {
parent = returnValue; // added
lastKey = part; // added
returnValue = parent[lastKey];
}
});
if(parent) {
delete parent[lastKey]; // added
}
return returnValue;
}
const obj = {"hello": {"data": {"a": "world", "b": "random"}}};
console.log(delProp(obj, 'hello.data.a'));
console.log(obj)
Also note that in JS for
loops are essentially more efficient than forEach
Array function. Thus I would change the related part a la:
for (const i = 0, i = keyParts.length; i++) {
// ...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With