ES6 / lodash -用startsWith检查嵌套对象值
ES6 / lodash - check nested Object values with startsWith
是否有任何函数或任何快速的方法来检查某个值是否在我们的对象开始与例如asd
的例子:
let obj = {
'child' : {
'child_key': 'asdfghhj'
},
'free': 'notasd',
'with': 'asdhaheg'
}
// check here if our obj has value that startsWith('asd')
对
如果你真的不关心哪个节点/值匹配,使用@trincot的解决方案。它很简单,写得很好,很有效地解决了你的问题。
如果你想要的不仅仅是一个布尔值作为你挖掘的结果,请继续阅读…
我真的怀疑你是否需要这样做,但是如果你的对象非常大,你会想要一个早期退出行为 -这意味着一旦找到匹配,通过输入数据的迭代将停止,true
/false
结果将立即返回。@trincot的解决方案提供了早期退出,但使用map
, filter
或reduce
的解决方案没有这种行为。
findDeep
比仅仅检查一个字符串值是否以另一个字符串值开头要有用得多——它需要一个应用于数据中的每个叶节点的高阶函数。
这个答案使用我的findDeep
过程来定义一个通用的anyStartsWith
过程,通过检查findDeep
是否返回undefined
(不匹配)
它将工作于任何输入类型,它将遍历Object
和Array
子节点。
const isObject = x=> Object(x) === x
const isArray = Array.isArray
const keys = Object.keys
const rest = ([x,...xs]) => xs
const findDeep = f => x => {
let make = (x,ks)=> ({node: x, keys: ks || keys(x)})
let processNode = (parents, path, {node, keys:[k,...ks]})=> {
if (k === undefined)
return loop(parents, rest(path))
else if (isArray(node[k]) || isObject(node[k]))
return loop([make(node[k]), make(node, ks), ...parents], [k, ...path])
else if (f(node[k], k))
return {parents, path: [k,...path], node}
else
return loop([{node, keys: ks}, ...parents], path)
}
let loop = ([node,...parents], path) => {
if (node === undefined)
return undefined
else
return processNode(parents, path, node)
}
return loop([make(x)], [])
}
const startsWith = x => y => y.indexOf(x) === 0
const anyStartsWith = x => xs => findDeep (startsWith(x)) (xs) !== undefined
let obj = {
'child' : {
'child_key': 'asdfghhj'
},
'free': 'notasd',
'with': 'asdhaheg'
}
console.log(anyStartsWith ('asd') (obj)) // true
console.log(anyStartsWith ('candy') (obj)) // false
你会发现这是一种浪费findDeep
的潜力,但如果你不需要它的力量,那么它就不适合你。
findDeep
的真正威力
findDeep (startsWith('asd')) (obj)
// =>
{
parents: [
{
node: {
child: {
child_key: 'asdfghhj'
},
free: 'notasd',
with: 'asdhaheg'
},
keys: [ 'free', 'with' ]
}
],
path: [ 'child_key', 'child' ],
node: {
child_key: 'asdfghhj'
}
}
结果对象有3个属性
-
parents
-在匹配值的谱系中对每个节点的完整对象引用 -
path
-获得匹配值的密钥路径(堆栈反转) -
node
-匹配 的键/值对
你可以看到,如果我们把父对象作为p
并反转路径堆栈,我们得到了匹配的值
p['child']['child_key']; //=> 'asdfghhj'
下面是ES6的一个函数:
function startsWithRecursive(obj, needle) {
return obj != null &&
(typeof obj === "object"
? Object.keys(obj).some( key => startsWithRecursive(obj[key], needle) )
: String(obj).startsWith(needle));
}
// Sample data
let obj = {
'child' : {
'child_key': 'asdfghhj'
},
'free': 'notasd',
'with': 'asdhaheg'
};
// Requests
console.log( 'obj, "asd":', startsWithRecursive(obj, 'asd' ) );
console.log( 'obj, "hello":', startsWithRecursive(obj, 'hello' ) );
console.log( 'null, "":', startsWithRecursive(null, '' ) );
console.log( 'undefined, "":', startsWithRecursive(undefined, '' ) );
console.log( '"test", "te":', startsWithRecursive('test', 'te' ) );
console.log( '12.5, 1:', startsWithRecursive(12.5, 1 ) );
解释:
函数是递归的:它在遍历嵌套对象结构时调用自己。作为obj
传递的值可以属于以下三种类型之一:
-
它相当于
null
(也像undefined
):在这种情况下,既不能进行递归调用,也不能调用startsWith
方法:结果是false
,因为这个值显然不是从给定的搜索字符串开始的; -
它是一个对象:在这种情况下,对象的属性值应该被检查。这将通过递归调用来完成。
some
方法确保一旦找到匹配项,迭代就停止,并且不再检查其他属性值。在这种情况下,some
返回true
。如果没有匹配的属性值,some
返回false
; -
以上皆非。在这种情况下,我们将其强制转换为string(通过应用
String
函数),并对其应用startsWith
。
在适用步骤中计算的值将作为函数结果返回。如果这是一个递归调用,它将被视为some
回调中的返回值,等等。
请注意,当您在字符串上调用该函数时,也会返回正确的结果,如下所示:
startsWithRecursive('test', 'te'); // true
非递归选择
为了回答关于潜在堆栈限制的评论,这里有一个替代的非递归函数,它在变量中维护一个"堆栈":
function startsWithRecursive(obj, needle) {
var stack = [obj];
while (stack.length) {
obj = stack.pop();
if (obj != null) {
if (typeof obj === "object") {
stack = stack.concat(Object.keys(obj).map( key => obj[key] ));
} else {
if (String(obj).startsWith(needle)) return true;
}
}
}
return false;
}
您可以使用find
函数递归迭代对象属性并检查属性是否以prefix
开头:
function hasPropertyStartingWith(obj, prefix) {
return !!Object.keys(obj).find(key => {
if (typeof obj[key] === 'object') {
return hasPropertyStartingWith(obj[key], prefix)
}
if (typeof obj[key] === 'string') {
return obj[key].startsWith(prefix)
}
return false
})
}
console.log(hasPropertyStartingWith(obj, 'asd'))
您可以使用一些简单的东西,如在JSON字符串上使用RegExp,如
var obj = {
'child': {
'child_key': 'asdfghhj'
},
'free': 'notasd',
'with': 'asdhaheg'
};
function customStartsWith(obj, prefix) {
return new RegExp(':"' + prefix + '[''s''S]*?"').test(JSON.stringify(obj));
}
console.log('obj, "asd":', customStartsWith(obj, 'asd'));
console.log('obj, "hello":', customStartsWith(obj, 'hello'));
console.log('null, "":', customStartsWith(null, ''));
console.log('undefined, "":', customStartsWith(undefined, ''));
console.log('"test", "te":', customStartsWith('test', 'te'));
console.log('12.5, 1:', customStartsWith(12.5, 1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.js"></script>
更新:另一个将在模糊环境中工作的递归对象行走器。这只是一个例子,它很容易定制。
var walk = returnExports;
var obj = {
'child': {
'child_key': 'asdfghhj'
},
'free': 'notasd',
'with': 'asdhaheg'
};
function customStartsWith(obj, prefix) {
var found = false;
walk(obj, Object.keys, function(value) {
if (typeof value === 'string' && value.startsWith(prefix)) {
found = true;
walk.BREAK;
}
});
return found;
}
console.log('obj, "asd":', customStartsWith(obj, 'asd'));
console.log('obj, "hello":', customStartsWith(obj, 'hello'));
console.log('null, "":', customStartsWith(null, ''));
console.log('undefined, "":', customStartsWith(undefined, ''));
console.log('"test", "te":', customStartsWith('test', 'te'));
console.log('12.5, 1:', customStartsWith(12.5, 1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.js"></script>
<script src="https://rawgithub.com/Xotic750/object-walk-x/master/lib/object-walk-x.js"></script>
- 正在检查对象javascript中是否存在嵌套属性
- 如何检查一个对象是否嵌套在另一个对象的属性中作为属性
- 如何检查主干模型中的嵌套属性是否已更改
- 检查嵌套的 JSON 结构是否包含键
- 检查嵌套对象是否被声明并且具有没有这么多条件检查的值
- 检查嵌套对象(对象数组)中是否存在属性设置为特定值的对象
- 正在检查嵌套指令中的已定义函数
- KnockoutJS:检查嵌套可排序项中的项是否被重新排序
- JS/MongoDB:检查对象(集合文档)中是否存在嵌套字段
- 使嵌套对象成为数组,并检查该键是否存在于objs中
- 检查对象的嵌套项的值
- mongoDB:检查文档中是否存在嵌套对象
- 如何检查嵌套标签的内容是否存在
- 如何检查JavaScript对象中嵌套的键是否可用
- 在嵌套的Jquery中检查父复选框
- 检查是否存在嵌套在对象深处的函数,这些函数可能不存在
- 使用Underscore has()检查嵌套属性
- ES6 / lodash -用startsWith检查嵌套对象值
- JavaScript,一种检查嵌套对象属性是否为null/undefined的优雅方式
- 在“if”条件下检查嵌套对象的更好方法