8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

通过字符串路径访问嵌套的 JavaScript 对象和数组

Jay Bienvenu 2月前

390 0

我有一个这样的数据结构:var someObject = {'part1': {'name':'第 1 部分','size':'20','qty':'50'},'part2': {'name':'第 2 部分',...

我有一个这样的数据结构:

var someObject = {
    'part1' : {
        'name': 'Part 1',
        'size': '20',
        'qty' : '50'
    },
    'part2' : {
        'name': 'Part 2',
        'size': '15',
        'qty' : '60'
    },
    'part3' : [
        {
            'name': 'Part 3A',
            'size': '10',
            'qty' : '20'
        }, {
            'name': 'Part 3B',
            'size': '5',
            'qty' : '20'
        }, {
            'name': 'Part 3C',
            'size': '7.5',
            'qty' : '20'
        }
    ]
};

我想使用这些变量访问数据:

var part1name = "part1.name";
var part2quantity = "part2.qty";
var part3name1 = "part3[0].name";

part1name 应填写 someObject.part1.name 的值,即 \'Part 1\'。part2quantity 也一样,填写 60。

有没有办法用纯 javascript 或 JQuery 来实现这一点?

帖子版权声明 1、本帖标题:通过字符串路径访问嵌套的 JavaScript 对象和数组
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Jay Bienvenu在本站《object》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 不确定您在这里问的是什么?您希望能够查询 part1.name 并返回文本 \'part1.name\'?或者您想要一种方法来获取存储在 part1.name 中的值?

  • @BonyT:我想查询 someObject.part1.name 并返回其值(“Part 1”)。但是,我希望查询(我称之为“键”)存储在变量“part1name”中。谢谢您的回复。@3nigma:我当然会这样做。但这不是我的本意。谢谢您的回复。

  • 我只是根据我已有的一些类似代码制作了这个,它似乎有效:

    Object.byString = function(o, s) {
        s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
        s = s.replace(/^\./, '');           // strip a leading dot
        var a = s.split('.');
        for (var i = 0, n = a.length; i < n; ++i) {
            var k = a[i];
            if (k in o) {
                o = o[k];
            } else {
                return;
            }
        }
        return o;
    }
    

    用法::

    Object.byString(someObj, 'part3[0].name');
    

    上的工作演示 http://jsfiddle.net/alnitak/hEsys/

    编辑 有些人注意到,如果传递的字符串最左侧的索引与对象内正确嵌套的条目不对应,此代码将抛出错误。这是一个合理的担忧,但恕我直言,最好在 try / catch 调用时使用块来解决,而不是让此函数默默返回 undefined 无效索引。

  • @t3dodson 我刚刚做了:github.com/capaj/object-resolve-path 请注意,当您的属性名称本身包含“[]”时,这不会很好地发挥作用。正则表达式会将其替换为“。”,并且它不会按预期工作

  • 很棒的东西;使用 lodash 库,还可以执行以下操作:_.get(object, nestedPropertyString);

  • 这可能会淹没在大量注释中,但是如果您尝试解决不存在的属性,则会出错。所以是“part3[0].name.iDontExist”。在 if in 中添加检查以查看 o 是否为对象可以修复此问题。(如何操作取决于您)。请参阅更新的小提琴:jsfiddle.net/hEsys/418

  • @ThatGuyRob 引入第三方库并不总是“更好”,而且无论如何,当我写这个答案时,这种方法甚至不存在。

  • lodash 现在支持此功能 _.get(obj, property) 。请参阅 https://lodash.com/docs#get

    来自文档的示例:

    var object = { 'a': [{ 'b': { 'c': 3 } }] };
    
    _.get(object, 'a[0].b.c');
    // → 3
    
    _.get(object, ['a', '0', 'b', 'c']);
    // → 3
    
    _.get(object, 'a.b.c', 'default');
    // → 'default'
    
  • 这应该是唯一可以接受的答案,因为这是唯一适用于点和括号语法的答案,并且当路径中的键的字符串中有“[]”时它不会失败。

  • 这是我使用的解决方案:

    function resolve(path, obj=self, separator='.') {
        var properties = Array.isArray(path) ? path : path.split(separator)
        return properties.reduce((prev, curr) => prev?.[curr], obj)
    }
    

    使用示例:

    // accessing property path on global scope
    resolve("document.body.style.width")
    // or
    resolve("style.width", document.body)
    
    // accessing array indexes
    // (someObject has been defined in the question)
    resolve("part3.0.size", someObject) // returns '10'
    
    // accessing non-existent properties
    // returns undefined when intermediate properties are not defined:
    resolve('properties.that.do.not.exist', {hello:'world'})
    
    // accessing properties with unusual keys by changing the separator
    var obj = { object: { 'a.property.name.with.periods': 42 } }
    resolve('object->a.property.name.with.periods', obj, '->') // returns 42
    
    // accessing properties with unusual keys by passing a property name array
    resolve(['object', 'a.property.name.with.periods'], obj) // returns 42
    

    限制:

    • 不能使用括号 ( [] ) 作为数组索引 - 尽管在分隔符标记之间指定数组索引(例如, . )可以正常工作,如上所示。
  • 使用 reduce 是一个很好的解决方案(也可以使用 underscore 或 lodash 库中的 _.reduce())

  • gpol 2月前 0 只看Ta
    引用 13

    @SC1000 好主意。这个答案是在大多数浏览器提供默认参数之前写的。我将把它更新为 \'function resolve(path, obj=self)\',因为引用全局对象作为默认值是故意的。

  • @AdamPlocher 我知道这已经过时了,但是我将其转换为 typescript,如下所示:export function resolvePath(path: string | string[], obj: any, Separator = '.') { const properties = Array.isArray(path) ? path : path.split(separator); return properties.reduce((prev, curr) => prev && prev[curr], obj); }

  • ES6 :Vanila JS 中只有一行(如果找不到则返回 null 而不是给出错误):

    'path.string'.split('.').reduce((p,c)=>p&&p[c]||null, MyOBJ)
    

    或者例如:

    'a.b.c'.split('.').reduce((p,c)=>p&&p[c]||null, {a:{b:{c:1}}})
    

    使用可选链接运算符

    'a.b.c'.split('.').reduce((p,c)=>p?.[c], {a:{b:{c:1}}})
    

    对于可立即使用的函数,它也能识别假、0 和负数,并接受默认值作为参数:

    const resolvePath = (object, path, defaultValue) => path
       .split('.')
       .reduce((o, p) => o ? o[p] : defaultValue, object)
    

    使用示例:

    resolvePath(window,'document.body') => <body>
    resolvePath(window,'document.body.xyz') => undefined
    resolvePath(window,'document.body.xyz', null) => null
    resolvePath(window,'document.body.xyz', 1) => 1
    

    奖金

    设置 路径(由@rob-gordon 请求),您可以使用:

    const setPath = (object, path, value) => path
       .split('.')
       .reduce((o,p,i) => o[p] = path.split('.').length === ++i ? value : o[p] || {}, object)
    

    例子:

    let myVar = {}
    setPath(myVar, 'a.b.c', 42) => 42
    console.log(myVar) => {a: {b: {c: 42}}}
    

    使用 [] 访问数组

    const resolvePath = (object, path, defaultValue) => path
       .split(/[\.\[\]\'\"]/)
       .filter(p => p)
       .reduce((o, p) => o ? o[p] : defaultValue, object)
    

    例子:

    const myVar = {a:{b:[{c:1}]}}
    resolvePath(myVar,'a.b[0].c') => 1
    resolvePath(myVar,'a["b"][\'0\'].c') => 1
    
  • 我喜欢这种技术。这真的很乱,但我想用这种技术进行赋值。 let o = {a:{b:{c:1}}}; let str = 'abc'; str.split('.').splice(0, str.split('.').length - 1).reduce((p,c)=>p&&p[c]||null, o)[str.split('.').slice(-1)] = \'some new value\';

  • 引用 17

    我喜欢使用 reduce 的想法,但对于 0、undefined 和 null 值,你的逻辑似乎不正确。{a:{b:{c:0}}} 返回 null 而不是 0。也许明确检查 null 或 undefined 将解决这些问题。(p,c)=>p === undefined || p === null ? undefined : p[c]

  • 你好@SmujMaiku,\'ready to use\' 函数正确返回 '0'、'undefined' 和 'null',我刚刚在控制台上测试过:resolvePath({a:{b:{c:0}}},'abc',null) => 0; 它检查键是否存在而不是值本身,从而避免多次检查

  • @AdrianoSpadoni 抱歉,我觉得我指出这一点的方式不太礼貌。祝您有美好的一天。

  • 请注意,在某些情况下,具有 defaultValue 的版本仍将返回未定义 - 例如 resolvePath({profile: {name: 'Bob'}}, 'profile.email', 'not set')。要解决这个问题,最后一行应该是 .reduce((o, p) => o?.[p] ?? defaultValue, object)

返回
作者最近主题: