1

is there a way to reference an object's key as a variable and then change its value? I'm trying this

const obj = {
  x: {
    y: {
      z: 'test'
    }
  }
}

const func = () => {
  let root = obj['x'];
  root = 'test 2';
}

func();

console.log(obj);

I'm trying to figure this out as I'm writing a recursive function in order to change root to something more like obj['x']['y']

totalnoob
  • 2,521
  • 8
  • 35
  • 69
  • `const key = 'x'; obj[key] = 'test 2';` – Robby Cornelissen Nov 15 '18 at 06:22
  • 1
    Can you illustrate what you want to do? And more importantly show an example of what you want the result to be? – Code-Apprentice Nov 15 '18 at 06:22
  • I'm trying to figure out why this isn't working https://stackoverflow.com/questions/53308903/building-a-menu-list-object-recursively-in-javascript so I simplified a part of that question as a new post – totalnoob Nov 15 '18 at 06:23
  • @RobbyCornelissen how would that work for obj['x']['y']? – totalnoob Nov 15 '18 at 06:24
  • `const key1 = 'x'; const key2 = 'y'; obj[key1][key2] = 'test 2';` – Robby Cornelissen Nov 15 '18 at 06:25
  • 1
    I'm thinking this question must have been asked before, but in two minutes of searching S.O. I couldn't find a duplicate. Can someone find a dupe? This seems like a super common problem with a relatively simple answer.... – Ray Toal Nov 15 '18 at 06:26
  • 1
    @RayToal There's a canonical duplicate somewhere, but am also coming up blank. – Robby Cornelissen Nov 15 '18 at 06:27
  • For the `obj[x][y]` access, [this answer](https://stackoverflow.com/questions/53277060/from-string-of-keys-to-hash-value/53277146#53277146) I wrote yesterday might provide some inspiration, although the use case is slightly different. – Robby Cornelissen Nov 15 '18 at 06:32

3 Answers3

2

If I understand your question correctly, the answer is probably "not without doing really weird stuff." What I believe you are asking is this. Given:

const obj = {
  x: {
    y: {
      z: 'test'
    }
  }
}

you want to store obj.x (equivalently, obj['x']) into a variable, in such a way that assigning to that variable will actually mutate the x field of object obj. Now you cannot do that. Once you make the binding:

let root = obj.x

Then reassigning root will NOT change obj at all: root is a distinct variable from obj. Draw a picture, it will help. However, root is essentially a pointer to obj.x so if you did:

root.y = 'test 2'

than this does mutate obj.x.y.

But, note you cannot assign obj.x to a variable and then use that variable to mutate the x field of obj. You can only mutate fields WITHIN obj.x. JavaScript does not have the ability to alias things (or make lvalues) like C++, for instance.

If you really want to update the x property of obj then you should put ONLY the string x into a variable like this:

root = 'x'

then you can do:

obj[root] = 'a new value for obj.x'

and this will mutate obj.x. But remember, you cannot first evaluate obj.x and then use that result to mutate obj.x. Well, I mean, not without doing some really nasty stuff like this:

root = 'obj.x';
eval(`${root} = 'a new value for obj.x';`);

But don't.

By the way, if obj was also a variable, then you could do this:

receiver = obj;
prop = 'x';
Reflect.set(receiver, prop, 'the new value')

Hopefully I guessed what you were trying to do. At any rate, maybe this answer will give some ideas.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
  • I think this is the best answer and the one I was looking for. I was confused with why https://stackoverflow.com/questions/53308903/building-a-menu-list-object-recursively-in-javascript didn't work – totalnoob Nov 15 '18 at 07:22
0
const func = () => {
  let root = obj['x'];
  root = 'test 2';
}

This reassigns the variable root to a new value and does not affect the object. Instead, assign to the object directly:

obj['x'] = 'test 2'

const obj = {
  x: {
    y: {
      z: 'test'
    }
  }
}

const func = () => {
  obj['x'] = 'test 2';
}

func();

console.log(obj);

Or you can change the value at a key via the root variable:

const obj = {
  x: {
    y: {
      z: 'test'
    }
  }
}

const func = () => {
  let root = obj['x'];
  root['y'] = 'test 3';
}

func();

console.log(obj);
Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • right, but if I were creating a recursive function like in https://stackoverflow.com/questions/53308903/building-a-menu-list-object-recursively-in-javascript where I needed a variable retain and to set its parent eg obj['x'] => obj['x']['y'] then that wouldn't work? – totalnoob Nov 15 '18 at 06:28
  • @totalnoob I don't understand what you mean by "I needed a variable retain and to set its parent". Reassigning a variable only changes the value of that variable and does not affect anything about its previous value. On the other hand, assigning to a key via a variable will affect all other references to the same object. – Code-Apprentice Nov 15 '18 at 06:30
  • 1
    @totalnoob These kinds of side effects are the source of many difficult-to-find bugs. I suggest you rethink your approach. – Code-Apprentice Nov 15 '18 at 06:33
  • I was trying to create a recursive function that iterated through an array and create nested values in an object. that function needed to know what root it's in and that root variable needed to change each time if there were multiple items in the array. – totalnoob Nov 15 '18 at 07:28
  • so if the array was ['x','y','z'], it'd create an object map like the one in this post, recursively and root would be obj['x'] => obj['x']['y'] => obj['x']['y']['z'] – totalnoob Nov 15 '18 at 07:29
0

Just pass the values

const obj = { x: { y: { z: 'test' } } }

delete Object.assign(obj, {newKey: obj.oldKey }).oldKey;

Shubham Sharma
  • 315
  • 2
  • 18