سؤال

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?

هل كانت مفيدة؟

المحلول

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 "."

نصائح أخرى

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')
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top