Pergunta

Say I have a nested object structure like:

var o = { a: { b: { c: 1 } } };

and I have a an accessor String like "a.b.c".

What's the fastest function to return the specified nested value (to any depth [1..n])?

I.e. in this case, getNested(o, 'a.b.c') === 1 and getNested(o, 'a') === {b:{c:1}}.

What's the best implementation of getNested?

Foi útil?

Solução

I hate to give an answer without profiling the code myself, but given that eval is probably slow, and forEach is slower than just running through a for-loop, I would start with:

// precondtion: path is a nonempty string
function getNested(obj, path) {
    var fields = path.split(".");
    var result = obj;
    for (var i = 0, n = fields.length; i < n; i++) {
        result = result[fields[i]];
    }
    return result;
}

But I would test this against other approaches.

I don't think that trying to optimize away the array construction on split would be worthwhile, but this is only one thing to try if you are interested in the fastest way.

ADDENDUM

Here is a transcript so you can see it in action:

$ node
> function getNested(obj, path) {
...     var fields = path.split(".");
...     var result = obj;
...     for (var i = 0, n = fields.length; i < n; i++) {
...         result = result[fields[i]];
...     }
...     return result;
... }
> var o = { a: { b: { c: 1 } } };
> getNested(o, "a")
{ b: { c: 1 } }
> getNested(o, "a.b.c")
1

** ADDENDUM 2 **

So embarassing -- I forgot the var in front of result before. That might speed it up a bit!

Other things to try:

  • Forget about the "optimization" with n and just do the for-loop test with i < test.length (might be optimized away anyway)
  • Replace split with substrings and indexOfs
  • Do the split with a regex /\./ instead of a raw string "."

Outras dicas

one more variant:

function getNested(obj, path) {
  path.replace(/[^\.]+/g, function (p) {
    obj = obj[p];
  });
  return obj;
}

Maybe something like this:

function getNested(o, path) {
    var parts = path.split('.');
    var member = o;
    while (member && parts.length) {
        member = member[parts.shift()];
    }
    return member;
}

It's probably not the fastest possible solution, but might be a useful starting point.

try{
   var prop=eval(string);
}
catch(er){
   prop=undefined;
}

My approach

var o = { a: { b: { c: 1 } } };
var getNested = function(p) {
    var t;
    p.split('.').forEach(function(e) {
        t = o[e] || t[e]
    });
    return t
}

you can try:

getNested('a.b.c')
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top