Question Details

No question body available.

Tags

javascript object

Answers (5)

Accepted Answer Available
Accepted Answer
November 2, 2025 Score: 9 Rep: 10,150 Quality: Expert Completeness: 60%

There are multiple issues with your code; most importantly you need to update the object you'll assign to, following the path you have followed to the current point.

In the following implementation, I defined the targetObject variable that follows the path from myObject up to the penultimate key (targetObject = targetObject[key]); all those values (targetObject[key]) need to be Objects. Then the targetObject will be assigned the value at the final key:

function myFunction(myObject, myArray) {
    const value = myArray.pop();
    let targetObject = myObject;
    for (let i = 0; i < myArray.length - 1; i++) {
        const key = myArray[i];
        if(!(targetObject[key] instanceof Object)){
            targetObject[key] = {};
        }
        targetObject = targetObject[key];
    }
    const key = myArray[myArray.length - 1];
    targetObject[key] = value;

return myObject; // not necessary if we have the original array }

Demo snippet:

function myFunction(myObject, myArray) {
    const value = myArray.pop();
    let targetObject = myObject;
    for (let i = 0; i < myArray.length - 1; i++) {
        const key = myArray[i]
        if(!(targetObject[key] instanceof Object)){
            targetObject[key] = {};
        }
        targetObject = targetObject[key];
    }
    const key = myArray[myArray.length - 1];
    targetObject[key] = value;

return myObject; }

const myLocalStorage = { users: { theme: 'westeros', notifications: { email: true, push: { infos: true } } }, admins: { // admin properties } }

const array1 = ["users", "notifications", "email", false]; myFunction(myLocalStorage, array1);

const array2 = ["users", "notifications", "sms", true] myFunction(myLocalStorage, array2)

console.log(myLocalStorage);

This can be written somewhat more concisely using Array#reduce:

function myFunction(myObject, myArray) {
    const value = myArray.pop();
    const lastKey = myArray.pop();
    const innerObject = myArray.reduce((targetObject, key) => {
        if(!(targetObject[key] instanceof Object)){
            targetObject[key] = {};
        }
        return targetObject[key];
    }, myObject );
    innerObject[lastKey] = value;
}

The same effect can be obtained through recursion, by calling recursively myFunction with an object ever more deep inside the structure of the original object and with an array ever smaller:

function myFunction(myObject, myArray){
    if(myArray.length === 0){
        return;
    }
    const key = myArray.shift();
    if(myArray.length === 1){
        myObject[key] = myArray[0];
    }
    else{
        if(!(myObject[key] instanceof Object)){
            myObject[key] = {}
        }
        myFunction(myObject[key], myArray);
    }
}

Demo snippet:

function myFunction(myObject, myArray){
    if(myArray.length === 0){
        return;
    }
    const key = myArray.shift();
    if(myArray.length === 1){
        myObject[key] = myArray[0];
    }
    else{
        if(!(myObject[key] instanceof Object)){
            myObject[key] = {}
        }
        myFunction(myObject[key], myArray);
    }
}

const myLocalStorage = { users: { theme: 'westeros', notifications: { email: true, push: { infos: true } } }, admins: { // admin properties } }

const array1 = ["users", "notifications", "email", false] myFunction(myLocalStorage, array1);

const array2 = ["users", "notifications", "sms", true] myFunction(myLocalStorage, array2)

console.log(myLocalStorage);

November 2, 2025 Score: 6 Rep: 387,930 Quality: Medium Completeness: 50%

You could pop the last key as well and iterate the path to final object.

This approach does not use the rest syntax, because the update data with keys and value is already an array.

function update(object, data) {
    const
        value = data.pop(),
        lastKey = data.pop();

let temp = object; for (const key of data) temp = temp[key] ??= {}; temp[lastKey] = value; return object; }

const myLocalStorage = { users: { theme: 'westeros', notifications: { email: true, push: { infos: true } } }, admins: { content: 'admin properties' } }, array1 = ["users", "notifications", "email", false];

console.log(update(myLocalStorage, array1));

November 2, 2025 Score: 4 Rep: 123,586 Quality: Medium Completeness: 80%

I afforded myself some fun creating an alternative for @kikon's fine answer.

The functionallity to update/add (nested) properties to an Object is pulled apart in a few functions.

The path passed to the updateProp function is now a string (properties divided with '.' or '/'). A non existing property will be added, an existing property will be modified. updateProp always returns the complete (modified) Object.

Maybe useful. Here's a more comprehensive codepen to fiddle with. Also as a small stackblitz project.

const myLocalStorage = {
  users: {
    theme: 'westeros',
    notifications: {
      email: true,
      push: {
        infos: true
      }
    }
  },
  admins: {}
};

// update or add a (nested) property to [obj] function updateProp(obj, { path, newValue } = {}) { const { found, lastKey } = maybePath(obj, path);

if (found) { found[lastKey] = newValue; }

return obj; }

// Examples log( updateProp(myLocalStorage, {path: "HELLO", newValue: "WORLD"}).HELLO, updateProp(myLocalStorage, {path: "HELLO", newValue: "WORLD"}).HELLO);

// Note: escaped key [...] (see resolvePath function) log( // an escaped key in the path [...]
+ updateProp(myLocalStorage, {path: "[HELLO / WORLD]", newValue: "WORLD"})+ ["HELLO / WORLD"], updateProp(myLocalStorage, {path: "[HELLO / WORLD]", newValue: "WORLD"}) ["HELLO / WORLD"]);

log( updateProp(myLocalStorage, {path: "users/notifications/email",+ newValue: [{address: "someone@somewhere.org", send: true}] })+ .users.notification.email, updateProp(myLocalStorage, { path: "users/notifications/email", newValue: [{address: "someone@somewhere.org", send: true}]}) .users.notifications.email);

log( updateProp(myLocalStorage, {path: "admins", newValue: "Mary"}).admins, updateProp(myLocalStorage, { path: "admins", newValue: "Mary" }).admins);

log( updateProp(myLocalStorage, {path: "admins", + newValue: { main: "Mary Bushel", local: "Mary Bushel's sister" } }) + .admins, updateProp(myLocalStorage, { path: "admins", newValue: { main: "Mary Bushel", local: "Mary Bushel's sister" } }) .admins);

log( updateProp(myLocalStorage) + // does nothing, returns [myLocalStorage], updateProp(myLocalStorage));

log( updateProp(myLocalStorage, {newValue: ""}) + // does nothing, returns [myLocalStorage], updateProp(myLocalStorage, {newValue: ""}));

// is maybeObject really an Object? function isObject(maybeObj) { return !Array.isArray(maybeObj) && maybeObj?.constructor === Object; }

// Extract an array from a (possible) path string // Note: a(n Object) key can be any string. // When a key contains dots or forward slashes // escape it using square brackets. // e.g. [my.key.here] or [my / key / here] function resolvePath(path) { path = path?.split(`) || [`]; const keys = []; let key = ``; let escaped = false;

for (let chr of path) { switch (true) { case chr === [: key = ""; escaped = true; break; case chr === ] && escaped: escaped = false; break; case !/[\/.\]]/.test(chr) || escaped: key += chr; break; default: keys.push(key); key = ""; escaped = false; } }

keys.push(key); return keys.map(v => v.trim()).filter(v => v.length > 0); }

// retrieve a path recursively from [obj] // with a given path array function retrievePath(obj, path) { const key = path.shift(); obj = key in obj && isObject(obj[key]) ? obj[key] : obj;

return path.length > 0 ? retrievePath(obj, path) : { found: obj, lastKey: key }; }

// try retrieving a path from [obj] with a // possible path array function maybePath(obj, path) { path = resolvePath(path); let lastKey = path?.at(-1) ?? null;

switch (true) { case path.length < 1: return { found: null, lastKey }; case path.length === 1: lastKey = path[0]; return { found: obj, lastKey }; default: return retrievePath(obj, path); } }

// demo: log to screen function log(cmd, obj) { document.body.insertAdjacentHTML(beforeend, `${cmd}
${JSON.stringify(obj, null, 2)}
`); }
code {
  background-color: rgb(227, 230, 232);
  color: rgb(12, 13, 14);
  padding: 0 4px;
  display: inline-block;
  border-radius: 4px;
  font-family: monospace;
  font-size: 85%;
  position: relative;
}

pre { margin-top: 0.2em; }

November 3, 2025 Score: 2 Rep: 81,195 Quality: Medium Completeness: 60%

You can iteratively get into the sub-objects of the object by the key array, create what's missing and update what's existing:

function myFunction(obj, array) {
    for (let index = 0; index < array.length - 2; index++) {
        if (!obj[array[index]]) {
            obj[array[index]] = {};
        }
        obj = obj[array[index]];
    }
    obj[array[array.length - 2]] = array[array.length - 1];
}

const myLocalStorage = { users: { theme: 'westeros', notifications: { email: true, push: { infos: true } } }, admins: { // admin properties } }; const array1 = ["users", "notifications", "email", false]; myFunction(myLocalStorage, array1); const array2 = ["users", "notifications", "sms", true]; myFunction(myLocalStorage, array2); console.log(myLocalStorage);

November 7, 2025 Score: 0 Rep: 19,352 Quality: Medium Completeness: 60%

Here's a set function that doesn't mutate both arguments but I've got to admit that the "cloning" bit is naive at best (most likely pure junk). Anyway there you go:

function set(o, path) {
    const clone = JSON.parse(JSON.stringify(o));
    function recur(acc, [key, ...rest]) {
        if (rest.length  {users: {notifications: {email: false}}}
n = set(n, ["users", "notifications", "email", true]);
//=> {users: {notifications: {email: true}}}
n = set(n, ["users", "notifications", "sms", true]);
//=> {users: {notifications: {email: true, sms: true}}}

p; //=> {}