以纯文本或带有props的数组访问对象路径

时间:2017-02-25 18:22:40

标签: javascript performance

考虑波纹管对象和存储在对象中的值的路径:

var obj = { a: 1, b: { a: { x: 2 }, b: 3 }, c: 4 }
var path = ["b", "a", "x"];

在对象路径中获取内容的最佳方式(最佳性能)是什么?

使用eval()

path = ["obj"].concat(path);
var value = eval(path.join("."));

循环

var _obj = obj;
for(key in path) {
    _obj = _obj[path[key]];
}
var value = _obj;

还有其他更好的方法来存储和查询对象复合体吗?

4 个答案:

答案 0 :(得分:3)

您可以使用路径并使用Array#reduce作为对象。

function getValue(object, path) {
    return path.reduce(function (o, k) {
        return (o || {})[k];
    }, object);
}

var obj = { a: 1, b: { a: { x: 2 }, b: 3 }, c: 4 }
    path = ["b", "a", "x"];

console.log(getValue(obj, path));

答案 1 :(得分:2)

递归版:

function getPath(obj, [head, ...tail]) {
  return !obj ? null : !head ? obj : getPath(obj[head], tail);
}

var obj = { a: 1, b: { a: { x: 2 }, b: 3 }, c: 4 };
var path = ["b", "a", "x"];

console.log(getPath(obj, path));

答案 2 :(得分:1)

eval很慢。循环很快,所以我建议您使用...

无聊版本:

var obj = { a: 1, b: { a: { x: 2 }, b: 3 }, c: 4 }
var path = ["b", "a", "x"];

function getDeep(object, path) {
  for (var i = 0; i < path.length; i++) {
    if (object == null) return
    object = object[path[i]]
  }
  return object
}

console.log(getDeep(obj, path)) //=> 2

答案 3 :(得分:1)

如果您知道您正在使用的那个对象具有该属性,那么您应该使用它:

const createAccesor = path => {
    let func = 'return obj'
    for (let i = 0; i < path.length; i++){
        func += `['${path[i]}']`
    }
    return Function('obj', func)
}
const obj = { a: 1, b: { a: { x: 2 }, b: 3 }, c: 4 }
const acces = createAccesor(['b', 'a', 'x'])
console.log(acces(obj))

这是 speed test 。 此解决方案的问题在于,当对象不包含您在路径中指定的prop时,它将抛出。

或使用效率较低的访问者:

const createAccesor = path => {
    let func = 'let temp=obj;'
    for (let i = 0; i < path.length; i++){
        func += `if(temp=temp['${path[i]}'])`
    }
    func += ';return temp'
    return Function('obj', func)
}
const obj = { a: 1, b: { a: { x: 2 }, b: 3 }, c: 4 }
const acces = createAccesor(['b', 'n', 'x', 'n'])
const acces2 = createAccesor(['b', 'a', 'x'])
console.log(acces(obj))
console.log(acces2(obj))

请注意,只有当您有多个“查询”对象或多次使用此对象时才会加速,否则您将无法获得任何速度。

eval的问题在于,如果它在内部函数中出现,则无法通过js引擎进行优化。

您也可以为自己创建“语法”,例如,而不是p array,您可以像'b->a->x''b.a.x'那样传递'acces string',然后只需调用split in function with / - &gt; / g或'。'它不会影响你的访问速度,它看起来更好看:D而且你不必写',所有的时间