遍历所有属性(包括数组 w/o 指定索引)和给定路径中的最后一项 returns 的对象遍历函数
Object traversal function that goes over all attributes (including arrays w/o specified index) and returns last item in given path
我正在尝试实现与 lodash 的 _.get()
类似的行为,但不同之处在于该函数将能够遍历路径中数组的 all/any 而不是在中指定索引路径(即 'abc.xyz[0]
)
// Example 1
const _object = {abc: {xyz: [{value: 1}, {value: 2}]}};
console.log(accumulateValues(_object, 'abc.xyz.value');
// Desired output: [{value: 1}, {value: 2}]
// Example 2
const _object = {abc: [{xyz: [{values: 1}]}]};
console.log(accumulateValues(_object, 'abc.xyz.values');
// Desired output: [1]
一个相当简单的方法,如果你想要 [1, 2]
可能看起来像这样:
const query = (path, ps = path .split ('.')) => (obj) =>
ps .reduce ((a, p) => a .flatMap (x => (x || {}) [p]) .filter (Boolean), [obj])
const _object = {abc: [{xyz: [{value: 1}, {value: 2}]}]}
console .log (query ('abc.xyz.value') (_object))
如果您正在寻找 [{value: 1}, {value: 2}]
,可能不会更难。但是如果不知何故,正如问题似乎暗示的那样,你想要任何一个结果,基于你如何包装'abc'
,那么我真的不明白你的要求。
这里一些节点周围的括号(例如[xyz]
)不增加任何值,因为我们简单地假设一直向下有一个数组,将初始值包装在一个数组中。如果您仍想提供它们,我们可以在处理前将它们移除:
const query = (path, ps = path .replace (/[\[\]]/g, '') .split ('.')) => (obj) =>
// ...
我们可能想改进这一点,通过在将输入包装成一个数组之前检查输入是否已经是一个数组来将数组放在根部。我把它留作练习。
这是一个使用 object-scan 的解决方案。它更灵活一些,例如,您可以使用 *
匹配未知属性或使用正则表达式匹配段等等(参见文档)。
// const objectScan = require('object-scan');
const f = (needle, obj) => objectScan([needle], {
useArraySelector: false,
rtn: 'value',
reverse: false
})(obj);
const o1 = { abc: { xyz: [{ value: 1 }, { value: 2 }] } };
const r1a = f('abc.xyz', o1);
console.log(r1a);
// => [ { value: 1 }, { value: 2 } ]
const r1b = f('abc.xyz.value', o1);
console.log(r1b);
// => [ 1, 2 ]
const o2 = { abc: [{ xyz: [{ values: 1 }] }] };
const r2a = f('abc.xyz.values', o2);
console.log(r2a);
// => [ 1 ]
const r2b = f('abc.*.values', o2);
console.log(r2b);
// => [ 1 ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@17.1.0"></script>
免责声明:我是object-scan
的作者
我正在尝试实现与 lodash 的 _.get()
类似的行为,但不同之处在于该函数将能够遍历路径中数组的 all/any 而不是在中指定索引路径(即 'abc.xyz[0]
)
// Example 1
const _object = {abc: {xyz: [{value: 1}, {value: 2}]}};
console.log(accumulateValues(_object, 'abc.xyz.value');
// Desired output: [{value: 1}, {value: 2}]
// Example 2
const _object = {abc: [{xyz: [{values: 1}]}]};
console.log(accumulateValues(_object, 'abc.xyz.values');
// Desired output: [1]
一个相当简单的方法,如果你想要 [1, 2]
可能看起来像这样:
const query = (path, ps = path .split ('.')) => (obj) =>
ps .reduce ((a, p) => a .flatMap (x => (x || {}) [p]) .filter (Boolean), [obj])
const _object = {abc: [{xyz: [{value: 1}, {value: 2}]}]}
console .log (query ('abc.xyz.value') (_object))
如果您正在寻找 [{value: 1}, {value: 2}]
,可能不会更难。但是如果不知何故,正如问题似乎暗示的那样,你想要任何一个结果,基于你如何包装'abc'
,那么我真的不明白你的要求。
这里一些节点周围的括号(例如[xyz]
)不增加任何值,因为我们简单地假设一直向下有一个数组,将初始值包装在一个数组中。如果您仍想提供它们,我们可以在处理前将它们移除:
const query = (path, ps = path .replace (/[\[\]]/g, '') .split ('.')) => (obj) =>
// ...
我们可能想改进这一点,通过在将输入包装成一个数组之前检查输入是否已经是一个数组来将数组放在根部。我把它留作练习。
这是一个使用 object-scan 的解决方案。它更灵活一些,例如,您可以使用 *
匹配未知属性或使用正则表达式匹配段等等(参见文档)。
// const objectScan = require('object-scan');
const f = (needle, obj) => objectScan([needle], {
useArraySelector: false,
rtn: 'value',
reverse: false
})(obj);
const o1 = { abc: { xyz: [{ value: 1 }, { value: 2 }] } };
const r1a = f('abc.xyz', o1);
console.log(r1a);
// => [ { value: 1 }, { value: 2 } ]
const r1b = f('abc.xyz.value', o1);
console.log(r1b);
// => [ 1, 2 ]
const o2 = { abc: [{ xyz: [{ values: 1 }] }] };
const r2a = f('abc.xyz.values', o2);
console.log(r2a);
// => [ 1 ]
const r2b = f('abc.*.values', o2);
console.log(r2b);
// => [ 1 ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@17.1.0"></script>
免责声明:我是object-scan
的作者