【问题标题】:Angular/JS/Typescript- Recursively access properties in an objectAngular/JS/Typescript- 递归访问对象中的属性
【发布时间】:2021-07-03 14:57:46
【问题描述】:

假设我有一个这样定义的对象:

const me = {
    id: 1,
    name: 'James',
    age: 40,
    family: {
        mother: {
            id: 101,
            name: 'Bea',
            age: 66
        },
        father: {
            id: 102,
            name: 'Martin',
            age: 69
        },
        children: [
            {
                id: 11,
                name: 'Tom',
                age: 18,
            },
            {
                id: 12,
                name: 'Nancy',
                age: 13,
            },
        ],
    },
}

如何通过提供一个由链接属性名称组成的字符串数组来轻松访问一个值? 例如,调用:

search(me, ['family', 'father', 'age'])

与以下内容相同:

me['family']['father']['age']

将返回69

附言: 让search(me, ['family', 'children', 'name']) 返回['Tom', 'Nancy'] 怎么样?

PSS: 甚至search(me, ['family', 'children', ['name', 'age']])返回

[
    {
        name: 'Tom',
        age: 18
    },
    {
        name: 'Nancy',
        age: 13
    }
]

编辑: 我去检查了 lodash/deepdash 库,但我自己并不能真正弄清楚。

【问题讨论】:

  • 看看Accessing nested JavaScript objects and arrays by string path 除了在你的情况下你已经有了数组(不需要分割路径)。
  • 到目前为止你尝试过什么?您是否尝试过为此编写实用程序函数?
  • 仅供参考,这不是 Java,所以:{'family', 'father', 'age'} 不是数组。
  • 你应该一次问一个问题,我已经回答了第一个问题,但是你的 PS 和 PSS 是不同的问题

标签: javascript arrays angular typescript properties


【解决方案1】:

您可以使用这个简单的递归函数来做到这一点,该函数将数组作为查询:

const me = {
    id: 1,
    name: 'James',
    age: 40,
    family: {
        mother: {
            id: 101,
            name: 'Bea',
            age: 66
        },
        father: {
            id: 102,
            name: 'Martin',
            age: 69
        },
        children: [
            {
                id: 11,
                name: 'Tom',
                age: 18,
            },
            {
                id: 12,
                name: 'Nancy',
                age: 13,
            },
        ],
    },
}


function search(obj, [first, ...rest]) {
  return rest.length ? search(obj[first], rest) : obj[first];
}

const result = search(me, ['family', 'father', 'age']);

console.log(result);

【讨论】:

  • 甚至是 ES6 单行代码:const search = (obj, [first, ...rest]) => rest.length ? search(obj[first], rest) : obj[first]
  • 是的,即使是这样 ?
  • 是的,我正在尝试使用数组参数进行类似的操作,但我没有让它工作......谢谢!
【解决方案2】:

虽然有点长,但您可以尝试所有组合。

const me={id:1,name:'James',age:40,family:{mother:{id:101,name:'Bea',age:66},father:{id:102,name:'Martin',age:69},children:[{id:11,name:'Tom',age:18,},{id:12,name:'Nancy',age:13,},],},}

function search(data, searchPattern) {
    const keys = [...searchPattern];
    
    //picking last key and it's corresponding value
    const lastKey = keys.pop();
    const resultInst = keys.reduce((acc,key)=>{
        return acc[key];
    }, data);
    
    // if it's array iterating it further to construct the response
    if (Array.isArray(resultInst)) {
        return resultInst.map(inst => {
            if (Array.isArray(lastKey)) {
                return lastKey.reduce((accInner,key) => {
                    accInner[key] = inst[key];
                    return accInner;
                }, {});
            } else {
                return inst[lastKey];
            }
        });
    } else {
        // else just returning property's value
        return resultInst[lastKey];
    }
}

console.log(search(me, ['family', 'father', 'age']))
console.log(search(me, ['family', 'children', 'name']))
console.log(search(me, ['family', 'children', ['name', 'age']]))

【讨论】:

    【解决方案3】:

    你有一些有趣的要求!这是使用object-scanlodash 的一体化答案

    // const objectScan = require('object-scan');
    // const lodash = require('lodash');
    
    const myData = { id: 1, name: 'James', age: 40, family: { mother: { id: 101, name: 'Bea', age: 66 }, father: { id: 102, name: 'Martin', age: 69 }, children: [{ id: 11, name: 'Tom', age: 18 }, { id: 12, name: 'Nancy', age: 13 }] } };
    
    const search = (data, needle) => objectScan([needle], {
      reverse: false,
      rtn: ['key', 'value'],
      useArraySelector: false,
      afterFn: (state) => {
        if (state.result.length === 0) {
          state.result = undefined;
        } else if (needle.includes('{')) {
          const prefixLength = lodash
            .zip(...state.result.map(([k]) => k))
            .findIndex((e) => new Set(e).size > 1);
          const result = [];
          state.result.forEach(([k, v]) => lodash.set(result, k.slice(prefixLength), v));
          state.result = result;
        } else if (
          state.result.length === 1
          && state.result.every(([k]) => k.every((p) => typeof p === 'string'))
        ) {
          state.result = state.result[0][1];
        } else {
          state.result = state.result.map(([k, v]) => v);
        }
      }
    })(data);
    
    console.log(search(myData, 'family.father.age'));
    // => 69
    
    console.log(search(myData, 'family.children.name'));
    // => [ 'Tom', 'Nancy' ]
    
    console.log(search(myData, 'family.children.{age,name}'));
    // => [ { name: 'Tom', age: 18 }, { name: 'Nancy', age: 13 } ]
    
    console.log(search(myData, 'family.father.unknown'));
    // => undefined
    .as-console-wrapper {max-height: 100% !important; top: 0}
    <script src="https://bundle.run/object-scan@16.0.2"></script>
    <script src="https://bundle.run/lodash@4.17.21"></script>

    免责声明:我是object-scan的作者

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-27
      • 2015-12-10
      • 2022-01-22
      • 2021-11-08
      • 2021-01-01
      • 2020-11-18
      • 2017-09-24
      相关资源
      最近更新 更多