1

Assume I have an object:

var abc = {
    a: 'a',
    b: 'b',
    c: {
      x: 'c',
      y: 'd'
    }
}

Now I want to fetch object values based on values present in an array below dynamically

var arr = ['a', 'b', 'c.x'] 
saurav ranjan
  • 131
  • 1
  • 2
  • 8

3 Answers3

3

NOTE: the following solution would work with the given scenario, where object properties are indicated using the dot notation, but will fail if you use bracket notation (e.g. c[x]).

const abc = {
  a: 'aVal',
  b: 'bVal',
  c: {
    x: 'cxVal',
    y: 'cyVal'
  },
  d: {
    x: 'dxVal',
    y: {
      z: 'dyzVal',
      w: 'dywVal'
    }
  }
};

const arr = ['a', 'b', 'c.x', 'd.y.w'];

function getValues(obj, keysArr) {
  return keysArr.map(key => {
    return key.split('.').reduce((acc, item) => {
      return acc[item];
    }, obj);
  });
}

const values = getValues(abc, arr);

console.log(values);
secan
  • 2,622
  • 1
  • 7
  • 24
  • Thanks for the answer.. Have a little confusion, why the acc object changes completely to the value of nested property while iteration. – saurav ranjan Oct 08 '20 at 16:08
  • `acc` is just a placeholder which is initialized with obj; at each iteration we dive deeper into the object, until we reach the intended property. Let's consider the `d.y.w` case: at the first iteration `acc` is the entire `abc` object and we return `abc[d]`; at the second iteration `acc` has become the `d` property of the `abc` object and we return `d[y]`; at the third iteration `acc` has become the `y` property of the `d` object and we return `y[w]`, [...continue...] – secan Oct 08 '20 at 16:25
  • as this is the last iteration, the final value returned by `reduce()` is exactly what we wanted: the `w` property of the `y` property of the `d` property of the `abc` object... that is to say `abc.d.y.w`. – secan Oct 08 '20 at 16:25
  • 1
    You can find more resources here: [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce), [W3School](https://www.w3schools.com/jsref/jsref_reduce.asp), [DigitalOcean](https://www.digitalocean.com/community/tutorials/js-finally-understand-reduce) – secan Oct 08 '20 at 16:30
0

You can create an extension like this:

Object.defineProperty(Object.prototype, 'valueAt', {
  value: function (location, defaultValue) {
    const routes = location.split('.');
    const lastRoute = routes.pop();

    let value = routes.reduce(
      (current, route) => current && current[route],
      this
    );

    if (value) return value[lastRoute] || defaultValue;
    else return defaultValue;
  },
  writable: true,
  configurable: true,
  enumerable: false,
});

and then use:

abc.valueAt("c.x");
Iosif
  • 812
  • 2
  • 15
0

You could split the strings for getting an array and reduce the keys by accessing the object.

var getValue = (object, keys) => keys.reduce((o, k) => (o || {})[k], object),
    object = { a: 'a', b: 'b', c: { x: 'c', y: 'd' } },
    keys = ['a', 'b', 'c.x'],
    result = keys.map(s => getValue(object, s.split('.')));

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392