【发布时间】:2017-05-24 09:05:15
【问题描述】:
如何支持 globstar 风格的 ** 搜索 JavaScript 对象?
这与 lodash 的 _.get 类似,只是要查询的对象可以包含这些特殊的 * 和 ** 属性,如果没有完全匹配,它们将被匹配。
在下面的示例代码中,{ **: { middleName: 3 }} 规则应与以下路径匹配:
['middleName']
['clients', 'middleName']
['clients', '0', 'middleName']
因为**匹配0个或多个元素,所以{**: { middleName: x }}本质上匹配任何以'middleName'结尾的数组并返回x。
但是,由于也有一个* 规则,它只匹配一个级别(恰好1 个元素具有任何值),它应该优先于**,导致第二条路径改为评估为{ lastName: 2 }。
在实践中,我不太关心优先级,因为不应该编写重叠的“规则”,但无论如何我都不知道如何实现**。
如果您需要一个更实际的示例,我打算将其用于:1、2、3 数字将替换为验证器函数,“路径”将是 <input> 名称。通过这种方式,我可以为我的表单指定验证规则。
另外,我真的只想返回叶节点,所以其中一个返回 { lastName: 2 } 的事实有点奇怪,但这是我不太关心的边缘情况。如果** 优先于此,因为它是叶节点匹配,我想那会更好。
代码:
function glob(object, path, defaultValue) {
let [first, ...rest] = path;
let value = object[first];
if (value === undefined) {
value = object['*'];
if (value === undefined) {
// TODO: support **
return defaultValue;
}
}
if (rest.length) {
return glob(value, rest, defaultValue);
}
return value;
}
let rules = {
firstName: 1, // matches ['firstName']
clients: {
'*': {
lastName: 2, // matches ['clients', anything, 'lastName']
}
},
'**': {
middleName: 3, // matches [...anything, 'middleName']
}
}
console.log(glob(rules, ['firstName'])); // 1
console.log(glob(rules, ['clients', '0', 'lastName'])); // 2
console.log(glob(rules, ['clients', '0', 'middleName'])); // should be 3
console.log(glob(rules, ['clients', 'middleName'])); // should be { lastName: 2 } or 3, whatever's easier to implement
console.log(glob(rules, ['middleName'])); // should be 3
【问题讨论】:
-
"如何支持 globstar 风格的 ** 通过 JavaScript 对象进行搜索?"你不是在搜索字符串数组(你称之为“路径”)吗?问题陈述可能不那么令人困惑。
-
@spinkus 是的,我知道这有点令人困惑,这就是我包含示例的原因。我不是在搜索数组/路径——路径被用作对象的键。这就像 lodash 的 _.get 一样,只是对象可以包含这些特殊的
*和**键。
标签: javascript search recursion glob