0

How can I reach into a object using an array and set a value - preferably without using eval, doing something like object[eval(["key", "deepkey"].split("")) = "newvalue"?

Doing it manually, I would just do object.key.deepkey = "newvalue", but again, I need to do this using an array to reach into the right property.

The object for reference:

object = {
  key: {
    deepKey: "value"
  }
}
Industrial
  • 41,400
  • 69
  • 194
  • 289

4 Answers4

2

You can write array type syntax as. jsfiddle

object = {
  key: {
    deepKey: "value"
  }
}

object['key']['deepkey']='newvalue'

if you have keys in array you can do this

var keys = ['key','deepkey'];
var obj = object;
for(var k =0; k <keys.length-1; k++){
   obj= obj[keys[k]];
}
obj[keys[k]] = 'newvalue'
Anoop
  • 23,044
  • 10
  • 62
  • 76
  • Sure, but this would only work with a two-level object where I know that the first level is named `key`. I need to be able to set nested values on unknown level. – Industrial Oct 14 '12 at 12:33
  • You can iterate through object using for in and set the values. – Anoop Oct 14 '12 at 12:34
2

You can use a recursive function to step through each level of the array (or object) like so:

function val(array, indices) {
    if(indices.length > 1) {
        var idx = indices.shift();
        return val(array[idx], indices);
    }
    else {
        return array[indices.shift()];
    }
}

var obj = { a: { b: 'c' } };

//result is 'c'
var result = val(obj, ['a', 'b']);

If you want to get an object reference, simply specify the second arg only up to that:

var obj = {
    a: {
        b: {
            c: 'foo'
        }
    }
};

var ref = val(obj, ['a', 'b']);

//ref is now obj.a.b, so you can do something like...
ref.x = 'bar';

console.dir(ref); //outputs something like { c: 'foo', x: 'bar' }
Jani Hartikainen
  • 42,745
  • 10
  • 68
  • 86
  • Thats nice, but how do I set the value of `b` in your example? – Industrial Oct 14 '12 at 12:41
  • @Industrial I'm sorry I didn't quite understand what you mean by that... `obj.a.b = foo`? Or do you actually want to use this function to get a reference to `b` instead of returning the value from it? – Jani Hartikainen Oct 14 '12 at 12:43
0

You can take the function from this question and rework it to access properties of an object.

http://jsfiddle.net/jbabey/Mu4rP/

var getPropByName = function (propName, context) {
    var namespaces = propName.split('.');

    for(var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }

    return context;
};

var myObject = {
    someKey: {
        deepKey: "value"
    }
};

myObject.someKey.deepKey; // "value"
getPropByName('someKey.deepKey', myObject); "value"
Community
  • 1
  • 1
jbabey
  • 45,965
  • 12
  • 71
  • 94
0

An alternative could be using Array.map this way:

function deepkey(obj,keys,set){
  var i=1
     ,kys = keys.split('.')
     ,exist = kys.map( function(k){
          var prev = this[i-1], isobj = prev.constructor === Object;
          this.push( isobj && k in prev ? prev[k] : prev);
          return (i++,this[i-1]);},
          [obj]
        )
     ,x = exist[exist.length-2];
  if (x && x.constructor === Object && set){
    x[kys[kys.length-1]] = set;
  }
  return x[kys.pop()] || null;
} 
// usage
var obj = { a:{ b:{ c:1, cc:{ d:{ e:{ a:1,b:2,c:3 } } } } } };
// assign [1,2,3,4,5] to obj.a.b.cc.d.e.b
console.log(deepkey(obj,'a.b.cc.d.e.b',[1,2,3,4,5])); //=> [1,2,3,4,5]
// get obj.a.b.cc.d.e.b[2]
console.log(deepkey(obj,'a.b.cc.d.e.b')[2]); //=> 3
// get non existing path obj.a.b.c.d.e.b
console.log(deepkey(obj,'a.b.c.d.e.b')); //=> null
KooiInc
  • 119,216
  • 31
  • 141
  • 177