javascriptobject

Updating object properties with array elements


I have an object with nested properties. I want to update those nested properties by using an array of elements that reflect the nested sequence of the object. Also if a property does not exist, then add it, otherwise only update it.

Problem: is that I got all properties separated (non nested) with just empty objects ...

This is the function I tried implementing

function myFunction(myObject, ...myArrray) {

    let value = myArrray.pop()

    for (let i = 0; i < myArrray.length; i++) {
        const element = myArrray[i]
        if (!myObject.hasOwnProperty(element)) {
            if (i == myArrray.length)
                myObject[element] = value
            else
                myObject[element] = {}
        }
        else {
            myObject[element] = myObject[i + 1]
        }
    }
    return myObject
}
const myLocalStorage = {
    users: {
        theme: 'westeros',
        notifications: {
            email: true,
            push: {
                infos: true
            }
        }
    },
    admins: {
        // admin properties
    }
}

Updating "email" property (which exists)


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

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

Solution

  • 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);