What's the fastest way to interpret a nested javascript object attribute accessor string?
-
25-10-2019 - |
سؤال
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 withi < test.length
(might be optimized away anyway) - Replace split with
substring
s andindexOf
s - 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')