2

I have the following string:

const str = "prop1.prop2.prop3"

I want to use this string to access the property prop3 of the following object:

const obj = {
   prop1: {
      prop2:{
         prop3:{
            // ---- destination point
         }
      }
   }
}

But I'm not able to figure out how to do it? there must be something that keeps adding the obj[currentProp] so on and so on. and.. isn't there a quicker method? I'm afraid I'm wasting my time on something that can be achieved more easily

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
Normal
  • 1,616
  • 15
  • 39
  • 1
    Does this answer your question? [Dynamically updating a JavaScript object from a string path](https://stackoverflow.com/questions/15092912/dynamically-updating-a-javascript-object-from-a-string-path) – thomas Jul 10 '22 at 12:44
  • 1
    This is a duplicate, but I can't find any of the old questions. You have to either write your own function or find one in a library. The language itself does not have a way to do this. – Pointy Jul 10 '22 at 12:44
  • 1
    lodash for example has set and get which are quite handy – cmgchess Jul 10 '22 at 12:45
  • This used to be called "object graph navigation", but that term may have faded into obscurity. There is/was a very nice library for Java (not JavaScript) called "OGNL", object graph navigation language. – Pointy Jul 10 '22 at 12:47
  • 1
    does this works for you [mpath](https://www.npmjs.com/package/mpath) – bogdanoff Jul 10 '22 at 12:49
  • @bogdanoff, yes. – Normal Jul 10 '22 at 12:50
  • @cmgchess, I'm using lodash, then great – Normal Jul 10 '22 at 12:50
  • @thomas, perhaps yes, but the question is too much complicated and the answers are even more complicated – Normal Jul 10 '22 at 12:52
  • @thomas, and the guy in the question is trying to access the prop in the object using the delimiter ">", while I'm trying to access it normally using the javascript way object dot notation – Normal Jul 10 '22 at 12:53
  • Does this answer your question? [How to convert dot notation string array into an object JavaScript and render to table?](https://stackoverflow.com/questions/72800339/how-to-convert-dot-notation-string-array-into-an-object-javascript-and-render-to) – Mohit Sharma Jul 10 '22 at 12:55
  • @MohitSharma, of course yes, but the guy is using React, how about keeping this question as a clean and simple reference for everyone? – Normal Jul 10 '22 at 12:56
  • @Normal but function work same for all with same requirements use `getDeepObjValue` to get your output. – Mohit Sharma Jul 10 '22 at 12:58
  • 1
    @MohitSharma. yes that's, true. but I also want the community to benefit as well. by asking an abstract and straightforward question. not everyone is using React. If I'm a beginner and I was to read that question, I wouldn't understand the JSX part of the questions/answers. – Normal Jul 10 '22 at 13:00

4 Answers4

6

This would be my approach:

const access = (path, object) => {
  return path.split('.').reduce((o, i) => o[i], object)
}

const obj = {
  prop1: {
    prop2: {
      prop3: {
        value: 'foo'
      }
    }
  }
}

const str = 'prop1.prop2.prop3'

console.log(access(str, obj)) // {"value": "foo"}
lukasl-dev
  • 724
  • 3
  • 11
1

You can combine split with forEach as follows:

const str = "prop1.prop2.prop3"

const obj = {
   prop1: {
      prop2:{
         prop3:{
            a: "b",
            c: "d"
         }
      }
   }
}

var srch = obj;

str.split(".").forEach(item => (srch = srch[item]));

console.log(srch); // { a: "b", c: "d"}
console.log(obj);

split converts str's value into an array, which is then looped and on each iteration, srch gets one level deeper.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • but that modifies the original obj in the memory because that's what `var srch = obj` exactly does – Normal Jul 10 '22 at 15:46
  • 1
    @Normal no, it does not. `srch` is a reference to a variable. If you say `a = 1; b = 1; a = 2`, that does not change `b`. Note that I did not change your elements of `obj`, I changed only the reference. I have edited my Fiddle to `console.log(obj);`. If you test it, you will see that `srch` is properly computed, while `obj` remained unchanged. – Lajos Arpad Jul 10 '22 at 16:05
  • 1
    yes, you're right – Normal Jul 10 '22 at 16:10
0

different ways to access a nested property of an object

using a function accessDeepProp with two arguments the object and path of the nested property!

Recursive way:

function accessDeepProp(obj, path) {
  if (!path) return obj;
  const properties = path.split(".");
  return accessDeepProp(obj[properties.shift()], properties.join("."));
}

For-loop way:

function accessDeepProp(obj, path) {
  const properties = path.split(".");
  for (let i = 0; i < properties.length; i++) {
    if (!obj) return null;
    obj = obj[properties[i]];
  }
  return obj;
}

Eval way: never_use_eval!

function accessDeepProp(objName, path) {
  try {
    return eval(`${objName}.${path}`);
  } catch (e) {
    return null;
  }
}

you could also use lodash get method

XMehdi01
  • 5,538
  • 2
  • 10
  • 34
-1

This is the shortest solution, and it supports arrays and ['bracket notation']. Just don't run it against malicious user input.

Update: a better(?) version without eval.

const obj = {
  prop1: {
    prop2: {
      prop3: {
        value: 'foo'
      }
    }
  }
}

const str = 'prop1.prop2.prop3'
//console.log(eval("obj." + str))

// a code without eval
var value = (Function("return obj." + str))();
console.log(value);
E_net4
  • 27,810
  • 13
  • 101
  • 139
IT goldman
  • 14,885
  • 2
  • 14
  • 28
  • no, it will be downvoted with reason; since eval has risk if you use it just *Never use eval()* – XMehdi01 Jul 10 '22 at 13:24
  • Is using `Function(body)` considered a better option"? – IT goldman Jul 10 '22 at 13:35
  • It has similar problems, and in this case there's a simpler and safer solution. – Pointy Jul 10 '22 at 13:36
  • if you add try catch it would be much safer! see my answer! – XMehdi01 Jul 10 '22 at 13:36
  • @Pointy Which lacks features vs the `eval`/`Function` version. I disagree to *never* use `eval`. If it's my data (and not arbitrary user data) I think it's ok to. – IT goldman Jul 10 '22 at 13:40
  • @ITgoldman yea "never" is a strong word. The main problem I have with `eval()` is about performance: V8 will not bother to optimize a function with an `eval()` call, because it really has no idea what it might do. – Pointy Jul 10 '22 at 17:40