-1

In a javascript object, is it possible to set property values of undefined nested keys by only using property accessors (e.g. dot notation or bracket notation)?

Lodash's _.set function (and T.J. Crowder's answer) is similar to what I want, but the structure of the code is different, i.e., _.set(state, "some.future.key", "baz").

Are there any libraries that would allow me to directly set the values, i.e., state.some.future.key = "baz"?

Ideally I would want the state to automatically assume the shape of:

state = {
    some: {
        future: {
            key: "baz"
        }
    }
}
t.c
  • 623
  • 5
  • 19
  • whats the purpose behind this? – Andrew Daly Jul 24 '19 at 08:19
  • @AndrewDaly Why does the purpose mater? – Dexygen Jul 24 '19 at 08:20
  • @Andrew I don't know the shape of the object in advance – t.c Jul 24 '19 at 08:21
  • @GeorgeJempty im curious! – Andrew Daly Jul 24 '19 at 08:24
  • Maybe [this discussion](https://stackoverflow.com/questions/18936915/dynamically-set-property-of-nested-object) might help you. – bdongus Jul 24 '19 at 08:25
  • @bdongus the discussion mentioned using lodash's _.set function which is similar to what I want, but the structure of the code is slightly different than what I would prefer (i.e. directly setting values of nonexistent keys). Is there any library that would allow me to directly set the values (similar to the style of immer)? – t.c Jul 24 '19 at 08:27
  • I know what you mean. I would prefer that too, but I never found a way to do that. Your path doesn't exist in memory, so you have to create it somehow. – bdongus Jul 24 '19 at 08:31
  • thanks @bdongus, perhaps that explains why lodash's _set function signature is structured so awkwardly. – t.c Jul 24 '19 at 08:33

3 Answers3

2

You simply create anything that's missing.

const state = {
    foo: "bar"
};

if (!state.some) {
    state.some = {};
}
if (!state.some.future) {
    state.some.future = {};
}
state.some.future.key = "baz";
console.log(state);

If it gets to be a lot of inline code, you can provide yourself a function to do it. The answers to this question and this question should get you headed the right way if you want to do that. A simplistic version:

function setDeep(obj, path, value) {
    if (typeof path === "string") {
        path = path.split(".");
    }
    const final = path[path.length - 1];
    path = path.slice(0, -1);
    for (const entry of path) {
        if (!obj[entry]) {
            obj = obj[entry] = {};
        } else {
            obj = obj[entry];
        }
    }
    return obj[final] = value;
}

const state = {
    foo: "bar"
};
setDeep(state, "some.future.key", "baz");
// Or: setDeep(state, ["some", "future", "key"], "baz");
console.log(state);

...but there are a dozen variations on that.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • I've read those links and although I could use something like lodash's _.set, the structure of the code is slightly different than what I would prefer (i.e. directly setting values of nonexistent keys) – t.c Jul 24 '19 at 08:25
  • 1
    @t.c - You *can't* directly set if the intermediary objects don't exist. There's no shorthand for it (other than a function, as above). – T.J. Crowder Jul 24 '19 at 08:28
0

The simplest way to solve this problem is the Proxy object as shown below:

const state = {
    foo: "bar"
}

var stateHandler = {

    get : function(obj,prop){
         if(obj[prop] == undefined){
            obj[prop]= new Proxy({},stateHandler);
         }
         return obj[prop];
    }
  };

var proxyState = new Proxy(state,stateHandler);

proxyState.koo.loo= 9; 
proxyState.too.noo.too.y = 10899;
console.log(proxyState.koo.loo); //9 
console.log(proxyState.too.noo.too.y); // 10899
console.log(proxyState.foo); // bar 

This will allow you to set property at any nested level.

debugmode
  • 936
  • 7
  • 13
-1

To do this state.some.future.key = "baz" use this code

state.foo='newbar';
state.some={};
state.some.future={};
state.some.future.key='baz';

and when you print state then you will get

state = {
    foo: "newbar",
    some: {
        future: {
            key: "baz"
        }
    }
}
SHUBHAM SINGH
  • 371
  • 3
  • 11