【问题标题】:JavaScript: Convert string and concatenate it to dynamically create an object property referenceJavaScript:转换字符串并将其连接以动态创建对象属性引用
【发布时间】:2017-10-18 15:15:32
【问题描述】:

我正在创建一个 API,其中值由服务器通过数据属性传递,因此 JS 可以用来检索信息...我的 JS 进行 AJAX 调用并返回一个 JSON 对象...

{
    "data": {
        "results": {
            "type": [
                {
                    "cars" : {
                        "brands": {
                            "ford" : {},
                            "honda" : {}
                        }
                    }
                }
            ]
        }
    }
}

为了得到品牌,我只是输入

let brand = data.result.type[0].cars.brands.ford

这样我可以获得我需要的结果,但我需要通过加入路径的 2 个部分来动态构建此路径。就像我在问题开头所说的那样,一些信息是通过数据属性传递的,信息是type[0].cars.brands.ford...我需要在我的代码中将它加入到data.result。我目前可以通过使用eval() 来获得想要的结果,就像这样

entry.querySelectorAll('[data-brand]').forEach((e) =>
    let brand = eval('data.result.' + e.dataset.brand);
)

我知道你们中的许多人会说使用 eval() 不好,我很清楚这一点,但我找不到更好的方法来实现这一点,还有另一个问题,当品牌,假设 nissan 不在 JSON 上,我收到错误 TypeError: Cannot read property 'nissan' of undefined... 可以通过在继续代码之前检查属性是否存在来避免这种情况,但我不知道该怎么做涉及eval() 时的测试。

所以...基本上,我需要的是一种更好的动态构建属性路径的方法,可以测试该属性是否存在...

提前谢谢...

【问题讨论】:

  • 你可以使用 data.result['property_name']
  • 感谢您的回答,但我已经尝试过了,但没有成功...
  • 究竟是什么不起作用?
  • @Jonasw 启发我
  • Jonas w 接受的答案完美运行...

标签: javascript json object ecmascript-6 eval


【解决方案1】:
const brand = e.dataset.brand.split(".").reduce((obj,id) => obj[id] || {}, data.results);

不支持括号,所以也支持:

type.0.whatever.keys

为不存在的键返回未定义(而不是空对象):

const brand = e.dataset.brand.split(".").reduce((obj,id) => (obj || {} )[id], data.results);

【讨论】:

  • 非常感谢...我不知道reduce()...我会研究更多...它工作得很好..我只需要调整数据属性,将type[0].cars.brands.ford 转为type.0.cars.brands.ford
  • 只有一个问题...我仍然收到TypeError: Cannot read property 'sentra' of undefined 因为品牌nissan 没有设置...所以,基本上这不存在type.0.cars.brands.nissan.sentra...我该怎么做当父属性不存在时停止reduce() 迭代?你知道吗?
  • 只有在nissan 是最后一项时才有效...当该项在中间时,实际上效果不佳...在我的示例中,品牌nissancomes before sentra 所以,reduce 为 false 时不会退出,它会继续搜索结果……那是错误发生的时候……
【解决方案2】:

您可以先检查 data.result 是否具有该属性,然后才能制作您的变量品牌:

if(data.result.hasOwnProperty(e.dataset.brand)){
    let brand = data.result[e.dataset.brand];
}

【讨论】:

  • 如果data.result 没有您循环访问的品牌,就会发生这种情况。
【解决方案3】:

你可以String#match找到所有key,然后使用Array#reduce迭代key,从对象中获取key值:

const obj = {"data":{"results":{"type":[{"cars":{"brands":{"ford":{"name":"ford"},"honda":{"name":"honda"}}}}]}}};

const brand = 'data.results.type[0].cars.brands.ford';

const getPathValue = (src, path) => path.match(/[^.\[\]]+/g)
    .reduce((p, k) => typeof p === 'object' ? p[k] : p, src);

const brandOBj = getPathValue(obj, brand);

console.log(brandOBj);

【讨论】:

    【解决方案4】:

    您可以检查即lodash get 方法,该方法允许您使用路径访问对象的值。

    如果 lodash 对您来说太大了,只需查看它们的实现即可。

    【讨论】:

      猜你喜欢
      • 2015-04-24
      • 1970-01-01
      • 2011-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-10
      • 1970-01-01
      相关资源
      最近更新 更多