0

i am trying to implement a function that uses array elements to access specific object properties for a situation like this:

let foo = {
    bar:{
        baz:"oldVal",
    }
}

let coodinates = ["bar", "baz"]

function accessAndModify(obj, coord, newVal){
    //should do this: obj[coord[0]][coord[1]]...[coord[coord.length - 1]] = newVal;
}

i have tried the following:

function accessAndModify(obj, coord, ewVal) {
    try {
        [obj, ...coord].reduce((x, y) => x[y]) = newVal;
    } catch (e) {
        return false;
    }
}

but it produced this error: ReferenceError: Invalid left-hand side in assignment.

4 Answers 4

1

The issue with your code is that you are traversing too far down the object hierarchy and your reduce is returning the value at obj['bar']['baz'] when you actually want obj['bar'] so that you can then set the baz element of that object to the new value. If you stop the reduce one element sooner your code works:

let foo = {
  bar: {
    baz: "oldVal",
  }
}

let coordinates = ["bar", "baz"]

function accessAndModify(obj, coord, newVal) {
  try {
    [obj, ...coord.slice(0, -1)].reduce((x, y) => x[y])[coord[coord.length - 1]] = newVal;
  } catch (e) {
    return false;
  }
}

console.log(foo);
accessAndModify(foo, coordinates, 'newVal');
console.log(foo);

Sign up to request clarification or add additional context in comments.

Comments

0

You need to assign the result of reduce() to an object and return the res.

function accessAndModify(obj, coord, newVal) {
    try {
        const res = [obj, ...coord].reduce((x, y) => x[y]) = newVal;
        return res;
    } catch (e) {
        return false;
    }
}

or return the result from reduce() directly.

function accessAndModify(obj, coord, newVal) {
    try {
        return [obj, ...coord].reduce((x, y) => x[y]) = newVal;
    } catch (e) {
        return false;
    }
}

Comments

0

You'll need to keep getting the next property deep in obj, but once yu are at the last one you need to set it before you return it, so that you are modifying an object property rather than a primitive. You could do it like this:

let foo = {
    bar:{
        baz:"oldVal",
    }
}

let coordinates = ["bar", "baz"]

function accessAndModify(obj, coord, newVal) {
    try {
        coord.reduce((carry, current, index) => {
            if (index === coord.length - 1) {
                carry[current] = newVal;
            }
            return carry[current];
        }, obj);
    } catch (e) {
        return false;
    }
}

accessAndModify(foo, coordinates, 'newVal');
console.log(foo);

Comments

0

Reduce takes an initial starting value as the second argument after the callback function, so you don't need to create a new array with the starting object, instead, set the initial value to the object.

Then, before you use reduce of coord, remove the last element from coord (using .pop()) and same it into a variable called last, this way you will get the last object so you can update its value, if you didn't extract the value then reduce will return the string value you're trying to update, rather than a reference to the object.

See example below:

let foo = {
  bar: {
    baz: "oldVal",
  }
}

let coordinates = ["bar", "baz"];

function accessAndModify(obj, coord, newVal) {
  try {
    const last = coord.pop(); // coord changes and last is assigned last value in array
    const foundObj = coord.reduce((x, y) => x[y], obj);
    foundObj[last] = newVal;
  } catch (e) {
    return false;
  }
}

accessAndModify(foo, coordinates, "newVal");
console.log(foo);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.