Angular/JS/Typescript- 递归访问对象中的属性
Angular/JS/Typescript- Recursively access properties in an object
假设我有一个这样定义的对象:
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']
会 return 69
.
PS:
如果有 search(me, ['family', 'children', 'name'])
return ['Tom', 'Nancy']
呢?
PSS:
甚至 search(me, ['family', 'children', ['name', 'age']])
returning
[
{
name: 'Tom',
age: 18
},
{
name: 'Nancy',
age: 13
}
]
编辑:
我去检查了 lodash/deepdash 个图书馆,但我自己真的弄不明白。
您可以使用将数组作为查询的简单递归函数来做到这一点:
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);
虽然有点长,但您可以尝试所有组合。
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']]))
你有一些有趣的要求!这是使用 object-scan and lodash
的一体化答案
// 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
的作者
假设我有一个这样定义的对象:
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']
会 return 69
.
PS:
如果有 search(me, ['family', 'children', 'name'])
return ['Tom', 'Nancy']
呢?
PSS:
甚至 search(me, ['family', 'children', ['name', 'age']])
returning
[
{
name: 'Tom',
age: 18
},
{
name: 'Nancy',
age: 13
}
]
编辑: 我去检查了 lodash/deepdash 个图书馆,但我自己真的弄不明白。
您可以使用将数组作为查询的简单递归函数来做到这一点:
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);
虽然有点长,但您可以尝试所有组合。
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']]))
你有一些有趣的要求!这是使用 object-scan and lodash
的一体化答案// 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
的作者