Set Nested Object Property by Path
This challenge focuses on a common JavaScript task: dynamically setting a value within a nested object structure. Often, you'll encounter data where the "path" to a specific property is not fixed but determined at runtime. Your goal is to create a function that can navigate this structure and update the target property.
Problem Description
You need to implement a JavaScript function setNestedProperty(obj, path, value) that takes three arguments:
obj: The target JavaScript object.path: A string representing the path to the property to be set. The path segments are separated by dots (e.g.,"user.address.city").value: The new value to assign to the property at the specifiedpath.
The function should:
- Modify the original object
objin place. - Create intermediate objects or arrays if they don't exist along the
path. - Handle paths that refer to array indices (e.g.,
"items.0.name"). - If
objis not an object ornull, or ifpathis not a non-empty string, the function should do nothing or throw an error (your choice, but be consistent).
Expected Behavior:
- If the
pathexists and the property can be set, thevalueshould be assigned. - If any part of the
pathleads to a non-object (and not an array index), the function should ideally create the necessary structure. For example, if the path is"a.b.c"andobj.aisundefined,obj.ashould become an object{}. Ifobj.ais5, this could be problematic and you might choose to overwrite it with an object. - If a path segment is a valid array index (a non-negative integer string), and the parent is an array, it should set the element at that index. If the parent is not an array, it should potentially create an array.
Examples
Example 1:
let obj = {
user: {
name: "Alice"
}
};
let path = "user.address.city";
let value = "New York";
setNestedProperty(obj, path, value);
// Expected Output:
// {
// user: {
// name: "Alice",
// address: {
// city: "New York"
// }
// }
// }
Explanation: The path user.address.city did not fully exist. The function created the address object within user and then set the city property to "New York".
Example 2:
let obj = {
data: [
{ id: 1, name: "Apple" }
]
};
let path = "data.0.price";
let value = 1.99;
setNestedProperty(obj, path, value);
// Expected Output:
// {
// data: [
// { id: 1, name: "Apple", price: 1.99 }
// ]
// }
Explanation: The path data.0.price referred to an element within an array. The function navigated to the first element of the data array and added a price property.
Example 3: (Edge Case - Overwriting a non-object)
let obj = {
settings: 123
};
let path = "settings.theme";
let value = "dark";
setNestedProperty(obj, path, value);
// Expected Output:
// {
// settings: {
// theme: "dark"
// }
// }
Explanation: The property settings was initially a number. The function detected that it needed to be an object to set the nested theme property, so it replaced the number 123 with an object { theme: "dark" }.
Example 4: (Edge Case - Path with array creation)
let obj = {
items: {}
};
let path = "items.0.name";
let value = "Banana";
setNestedProperty(obj, path, value);
// Expected Output:
// {
// items: [
// { name: "Banana" }
// ]
// }
Explanation: The items property was an object, but the path indicated an array index (0). The function converted items to an array and created the first element as an object with the name property.
Constraints
- The
pathstring will only contain alphanumeric characters, dots (.), and digits. - The
pathstring will not start or end with a dot. - There will not be consecutive dots in the
pathstring. - The
objwill be a valid JavaScript object, array, or primitive value that might need to be converted. - The
valuecan be any JavaScript data type. - The function should be reasonably efficient for paths up to 10 segments deep and objects with up to 1000 properties/elements.
Notes
- Consider how you will split the
pathstring into individual segments. - Pay close attention to differentiating between object properties and array indices. A segment that is a string representing a non-negative integer should be treated as an array index if the parent is an array, or potentially trigger an array conversion if the parent is not an array but needs to become one.
- Think about the initial state of the object and how to handle cases where intermediate paths don't exist.
- You might find it helpful to use a loop and keep track of the current level in the object structure.
- Consider using
hasOwnPropertyor checkingtypeofto ensure you are working with objects or arrays correctly.