7

Context: I'm writing a Redux reducer (although this question is not Redux-specific) for my app's settings, which is a nested object. I want to modify the settings object using property names that are given dynamically.

Example:

const settings = {
  service: {
    username: 'TEST',
    password: ''
  }
}

// Normally this would be passed by Redux, but for the purposes of this exercise it's hardcoded

const settingKey = 'service.username';

console.log(settings[settingKey]); // undefined

console.log(eval(`settings.${settingKey}`)); // works, but bad

The only way I can think of accessing the subobject without using eval is using a regex to split the settingKey into its component parts:

const match = /(.+)\.(.+)/.exec(settingKey);
console.log(settings[match[1]][match[2]];

const settings = {
  service: {
      username: 'TEST',
      password: ''
  }
}

const settingKey = 'service.username';

const match = /(.+)\.(.+)/.exec(settingKey);

console.log(settings[match[1]][match[2]]);

This works, but

  1. It's ugly
  2. It doesn't work for more deeply nested objects

Is there a way of accessing a nested object's properties with a dynamic name without using regexes or eval?

0

3 Answers 3

5

You can do something like this,

var settings = {service: {username: 'TEST', password: ''}}
var key = "service.username";

function getValue(obj, keys){
  keys.split(".").forEach(function(itm){
    obj = obj[itm];
  });
  return obj;
}

getValue(settings, key); //"TEST"

Or you can do it simply using Array#reduce,

var settings = {service: {username: 'TEST', password: ''}}
var key = "service.username", result = key.split(".").reduce((a,b) => a[b], settings);
console.log(result); // "TEST"
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. I was hoping there would be a nicer way, but this will have to do.
ES6 version: settingName.split('.').reduce((prev, itm) => prev[itm], settings)
@marksomnian We had similar intuitions.. :)
0

Another option that doesn't use eval and works with nested properties.

var settings = {service: {username: 'TEST', password: ''}}
var key = "service.username";
console.log(Function('setting', 'return settings.' + key)(settings));

4 Comments

I didn't even know you could do this. Seems a bit eval-ly, but still cool.
Isn't this just eval() by another name?
@nnnnnn Read here.
So in other words... yes, they're the same thing for this purpose, where the input is in a known format.
-1

I think you just change one bit:

const settings = {
  service: {
    username: 'TEST',
    password: ''
  }
}
console.log(settings['service'].username);

2 Comments

This does not answer the question. The ['service'].username is not known at runtime (all I have is service.username).
i don't understand you. Can you explain more clearly ??

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.