使用其完整路径访问对象的属性值

时间:2016-10-31 09:29:08

标签: javascript google-chrome object nested

我有一个包含许多嵌套元素的对象,比如

var out = {
   "parentOne":{
      "subParentOne":{
         "childOne":0,
         "childTwo":0
      },
      "subParentTwo":{
         "otherChildOne":0,
         "otherChileTwo":0
      }
   },
   "parentTwo":{
    [...]
   }
}

对象中总共有269个不同的属性。

我有一个包含"路径"的数组。我需要检索的属性如下:

var prop = ["parentOne.subParentOne.childOne", "parentOne.subParentTwo.otherChildTwo"]

所以这个数组最多可以包含269个元素。

要访问子键的值,请使用以下代码:

    for (let p in prop) {
        var result = out
        var keys = prop[p].split(".")
        for (let k in keys) {
            result = result[keys[k]]
        }
        // do stuff with the value
    }

但效率非常低,所以我正在寻找更好的解决方案。

为什么这不起作用?

   var result = out["parentOne.subParentOne.childOne"]

那么实现这一目标的最佳方法是什么?

(请注意我在electron之上构建我的应用,所以我只对谷歌浏览器的工作解决方案感兴趣)

编辑

忘了说对象属性可以改变。目前,在启动应用程序后,我向服务器发送请求,获取示例输出并解析结果以使用此方法获取可用密钥:

var availableKeys = []
parseKey(out, '')

function parseKey(object, root) {
        for (let key in object) {
            switch (typeof object[key]) {
                case 'object':
                    parseKey(object[key], (root === '' ? key : root + '.' + key))
                    break
                case 'number':
                    availableKeys.push((root === '' ? '' : root + '.') + key)
                    break
                default:
                    break
            }
        }
    }

3 个答案:

答案 0 :(得分:2)

  

但效率很低......

不,不是。它是一个字符串拆分,后跟循环访问对象上的一些属性。除了分割(最小)的开销和循环的开销(最小)之外,它与out.parentOne.subParentOne.childOne一样有效。

  

为什么这不起作用?

var result = out["parentOne.subParentOne.childOne"]

因为那里正在寻找一个名为parentOne.subParentOne.childOne的属性,这是一个完全有效的JavaScript对象属性名称:

var out = {
  "parentOne.subParentOne.childOne": "here's the value"
};
console.log(out["parentOne.subParentOne.childOne"]);

  

那么实现这一目标的最佳方法是什么?

您在问题中显示的方式,和/或各种方式detailed in the answers to this question,这些方法将从根本上归结为拆分字符串,然后按照问题中的代码降低对象层次结构。

答案 1 :(得分:1)

这不能直接回答您如何处理a.b.c等“属性路径”的问题。 TJ Crowder引用的答案很好地涵盖了这一点。这个答案谈到了其他方法。

一般来说,如果我想进行一些处理A,我有两种选择。一种是用我的宿主语言写下A的逻辑。我可以用某种方式将该程序与“名称”相关联,这样我就可以查找并在需要时执行它。另一种选择是发明一种语言(通常称为“DSL”),它允许我以A'的形式更简洁地表达我的处理要求。然后,我为DSL编写一个解释器来解析A'并实际执行处理A.

在您的情况下,您选择了第二种选择。您的DSL是以点分隔的属性路径,例如a.b.c,解析器是您编写的代码。这没有任何问题,并且没有真正的性能问题。但它可能没有必要。相反,请考虑将您的指标表达为JS函数:

const myMetrics = {
  metric1: obj => obj.parentOne.subParentOne.childOne,
  ...
}

现在,当用户选择"metric1"时,您只需点击myMetrics[metricName](out)即可检索所需的指标。

这似乎是一个神秘的差异。但是,请考虑用户选择的特定度量可能对应于比简单嵌套属性引用更复杂的情况的情况。也许度量标准具有带日期字段的数组值,并且您希望为该度量标准选择最新值。在这种情况下,使用DSL(属性路径)方法,您需要扩展您的DSL以允许类似parentOne.subParentOne[@latest].childOne之类的东西,仅作为示例,并相应地扩展解释器。事情很快就会失控 - 不久之后你可能会重新实现相当于jq的东西。通过将每个用户可选择的度量直接与JS函数相关联的方法,您可以编写任意复杂度的定义。

答案 2 :(得分:0)

这似乎已得到解答,但我认为可能有一个更简单的解决方案。可能是一个单行解决方案,使用JS Array.prototype.map。根据您的解释,您似乎已经知道JSON结构中的级别数为3.您可以执行此操作以返回与prop键对应的值:

var values = prop.map(key => {var parts = key.split("."); return out[parts[0]][parts[1]][parts[2]];});

上面将以与props中的键相同的顺序返回数组中的值。

我写了一个库RichFlow,可以帮助你在JavaScript中进行更多的数据处理。可以在http://richflow.richboy.me/

获取该库的实时浏览器内测试

恰好可以通过简单的数组处理轻松解决这个问题,因为你已经有了生成多键字符串的函数