2

Say I have the following object:

let exampleObj = {
   hello: {
      there: {
         friend: 'my friend!',
         neighbor: 'neighbor!',
         world: 'world!'
      }
   }
}

Is there an efficient way I can create a function such as

function getPropValues(obj, ...keys) {
 // ...
}

where if I call getPropValues with the following arguments

const result = getPropValues(exampleObj, 'hello', 'there', 'world');

It would give me the result of exampleObj['hello']['there']['world']?

(i.e. I would expect result to be 'world!' in this case)

6
  • 'hello', 'there', 'world' reliably navigates to the property you want? Commented May 10, 2021 at 23:27
  • @connexo yes but I want the function to be able to dynamically do it, i.e. pass in any values. the object (and property names) will not always be the same. That was just an example. Commented May 10, 2021 at 23:28
  • I think connexo is asking if you need to support error cases (ie, is it possible the property doesn't exist) Commented May 10, 2021 at 23:29
  • you could mitigate that with hasOwnProperty though? Commented May 10, 2021 at 23:30
  • @NicholasTower oh okay -- no need to handle error cases, for this function, it is safe to assume we are passing in correct values and that they will exist in the object. Commented May 10, 2021 at 23:32

4 Answers 4

5

you can do this

function getPropValues(obj, ...keys) {
    return keys.reduce((p, c) => {
        return p[c]
    }, obj)
}

Sign up to request clarification or add additional context in comments.

Comments

4

Use Array.prototype.reduce() with Optional chaining ?. as a fallback to undefined for missing properties:

const exampleObj = {
  hello: {
    there: {
      friend: 'my friend!',
      neighbor: 'neighbor!',
      world: 'world!'
    }
  }
};

const getVal = (ob, ...k) => k.reduce((o, k) => o?.[k], ob);

console.log( getVal(exampleObj, "hello", "there", "world") ); // "world!"
console.log( getVal(exampleObj, "hello", "stranger") );       // undefined

Or if you like a dotted string notation:
(Be careful since bug-prone. Properties can also have dots)

const exampleObj = {
  hello: {
    there: {
      friend: 'my friend!',
      neighbor: 'neighbor!',
      world: 'world!'
    }
  }
};

const getVal = (ob, s) => s.split('.').reduce((o, k) => o?.[k], ob);

console.log( getVal(exampleObj, "hello.there.world") ); // "world!"
console.log( getVal(exampleObj, "hello.stranger") );    // undefined

1 Comment

This seems like a helpful comment on @dasi's answer
0

You can easily achieve this using recursion.

let exampleObj = {
  hello: {
    there: {
      friend: "my friend!",
      neighbor: "neighbor!",
      world: "world!",
    },
  },
};

function getPropValuesWithIndex(obj, keys, index) {
  if (index === keys.length - 1) return obj[keys[index]];
  return getPropValuesWithIndex(obj[keys[index]], keys, index + 1);
}

function getPropValues(obj, ...keys) {
  return getPropValuesWithIndex(obj, keys, 0);
}

const result1 = getPropValues(exampleObj, "hello", "there", "world");
console.log(result1);

const result2 = getPropValues(exampleObj, "hello", "there", "friend");
console.log(result2);

Comments

0

Here's a much simpler recursive version in only one function, without using index.

let exampleObj = {
  hello: {
    there: {
      friend: 'my friend!',
      neighbor: 'neighbor!',
      world: 'world!',
    },
  },
};

function getPropValues(obj, ...keys) {
  let currentObj;
  let key = keys.shift();
  if (keys.length && typeof obj[key] === 'object') {
    currentObj = obj[key];
    return getPropValues(currentObj, ...keys);
  } else return obj[key];
}

const result = getPropValues(exampleObj, 'hello', 'there', 'world');

console.log(result);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.