0

I have a funciton that accept a property name

func(propertyName) {
  return object[propertyName];
}

so by calling func('value') will return the object.value

However the object is complex, so it has inner props

What I want to do is to be able to do that func('property1.property2')

What is the best way to do that?

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Sergino
  • 10,128
  • 30
  • 98
  • 159
  • Does this answer your question? [Accessing nested JavaScript objects and arrays by string path](https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arrays-by-string-path) – CBroe Oct 22 '21 at 11:14
  • `let property = {name:'test'} function test(prop) { console.log(prop) } test(property.name)` – bZezzz Oct 22 '21 at 11:15

2 Answers2

1

A combination of reduce and the Optional chaining operator ensures both a fail safe implementation and a fail safe access of any passed property key path at any passed type/object ...

function getValueByKeyPath(obj, path) {
  return String(path)
    .split('.')
    .reduce((value, key) => value?.[key], Object(obj))
}

const sampleData = {
  foo: {
    value: 'foo',
    bar: {
      value: 'bar',
      baz: {
        value: 'baz',
      },
    },
  },
};

console.log(
  "getValueByKeyPath(sampleData, 'foo.bar.baz') ...",
  getValueByKeyPath(sampleData, 'foo.bar.baz')
);
console.log(
  "getValueByKeyPath(sampleData, 'foo.bar.baz.value') ...",
  getValueByKeyPath(sampleData, 'foo.bar.baz.value')
);

console.log(
  "\nfail safe ... getValueByKeyPath(sampleData, 'foo.biz.baz.value') ...",
  getValueByKeyPath(sampleData, 'foo.biz.baz.value')
);

console.log(
  "\nfail safe ... getValueByKeyPath('', 'toString') ...",
  getValueByKeyPath('', 'toString')
);
console.log(
  "fail safe ... getValueByKeyPath(null, '') ...",
  getValueByKeyPath(null, '')
);
console.log(
  "fail safe ... getValueByKeyPath() ...",
  getValueByKeyPath()
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

The above approach can be extended to bracket notation with both quoted and unquoted keys for e.g. nested/mixed object and array based data-structures. Then one does not split the key-path at simply any dot but also at any opening and closing bracket while capturing the value inside the brackets. The result of this split operation needs to be sanitized from some falsy artifacts, the reducing part stays the same ...

function getValueByKeyPath(obj, path) {
  return String(path)
    .split(/\.|\[['"]?([^'"\]]*)['"]?\]/)
    .filter(elm => !!elm)
    .reduce((value, key) => value?.[key], Object(obj))
}

const sampleDataA = {
  foo: {
    value: 'foo',
    bar: {
      value: 'bar',
      baz: {
        value: 'baz',
      },
    },
  },
};
const sampleDataB = {
  foo: {
    bar: [{
      baz: {
        value: 'baz',
        biz: {
          value: 'biz',
        },
      }
    }, {
      buzz: {
        value: 'buzz',
        booz: {
          value: 'booz',
        },
      }
    }],
  },
};

console.log(
  "getValueByKeyPath(sampleDataA, 'foo.bar.baz.value') ...",
  getValueByKeyPath(sampleDataA, 'foo.bar.baz.value')
);
console.log(
  "getValueByKeyPath(sampleDataA, 'foo.bar[\"baz\"].value') ...",
  getValueByKeyPath(sampleDataA, 'foo.bar["baz"].value')
);
console.log(
  "getValueByKeyPath(sampleDataB, 'foo.bar[1][\"buzz\"].booz') ...",
  getValueByKeyPath(sampleDataB, 'foo.bar[1]["buzz"].booz')
);
console.log(
  "fail safe ... getValueByKeyPath(sampleDataB, 'foo.bar[2].buzz.booz') ...",
  getValueByKeyPath(sampleDataB, 'foo.bar[2].buzz.booz')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • btw [the highest rated and accepted answer](https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arrays-by-string-path#answer-6491621) of the above posted duplicate link fails if one invokes it like `Object.byString(sampleDataB, 'foo.bar[1]["buzz"].booz');` whereas it does work for `Object.byString(sampleDataB, 'foo.bar[1].buzz.booz')`. Thus the provided implementation of `Object.byString` is not reliable if it comes to a proper handling of bracket notation with quoted strings. – Peter Seliger Oct 22 '21 at 15:22
  • I like this one from the same thread https://stackoverflow.com/a/41326547/2926340 – Sergino Oct 25 '21 at 05:55
  • @sreginogemoh ... well, the basic idea behind both approaches is the same. Both approaches too, focus on handling unreliable arguments and on how to exit the iteration with a ready consumed object. Yet I would say the 3 commands (chained operations) of `.split().filter().reduce()` are more expressive/readable than the linked approach with its `for` loop and the handling of `continue` and the multiple `return`s. – Peter Seliger Oct 25 '21 at 09:00
0

try this:

example data: a={b:{c:"hellooo"}};

function: function getValue(object,propertyName){ return propertyName.split(".").reduce((a,c)=>a[c],object); }

response:

getValue(a,"b.c") = hellooo

Cem Tuğut
  • 97
  • 6