javascript - 如何理解 javascript react 中的这段代码
问题描述
我在网上找到了js中函数的实现,这个函数递归地过滤了一个对象数组,每个对象可能有属性“children”,它是对象数组,对象也可能有孩子等等。该功能正常工作,但我有点不明白。
这是我的功能:
getFilteredArray (array, key, searchString) {
const res = array.filter(function iter(o) {
if (o[key].toLowerCase().includes(searchString.toLowerCase())) {
return true;
}
if(o.children){
return (o.children = o.children.filter(iter)).length;
}
});
this.setState({
filteredArray: res
});
}
我不明白这段代码:
if(o.children){
return (o.children = o.children.filter(iter)).length;
}
我们可以简化这个表达式(o.children = o.children.filter(iter)).length;
吗?
为什么我们返回数组的长度而不是数组本身?
函数“iter”接受一个参数,即对象。为什么我们只写 o.children.filter(iter) 而不将任何参数传递给这里的“iter”?根据递归教程,如果函数需要参数,总是会传递参数。但是在这里我们没有通过,这很奇怪。
解决方案
这是一个重写,力求清晰并稍微简化逻辑以消除干扰:
const recursivelyFilter = (arr, key, searchString) => {
return arr.filter(function iter(obj) {
if (obj[key].includes(searchString)) {
return true;
}
if (obj.children) {
obj.children = obj.children.filter(child => iter(child));
return obj.children.length > 0;
}
return false;
});
};
Array#filter
是这段代码的核心。filter
接受一个回调,它应该返回一个布尔值以确定一个元素是否将包含在结果数组中。它不能就地工作。
基本情况(递归的终止条件)是:
- 如果当前对象(树中的一个节点)有一个键匹配,则返回 true。
key
searchTerm
- 如果当前节点不匹配
searchTerm
且没有子节点,则返回 false。在原始代码中,返回undefined
默认为 false。
递归情况是:
- 如果当前节点有子节点,则使用
iter
函数的布尔结果递归过滤它们。如果当前节点的至少一个后代通过了过滤条件,则将当前节点包含在其父children
数组中,否则将其删除。该代码将新子数组的长度视为布尔值以实现此目的。
return (o.children = o.children.filter(iter)).length;
首先执行对 的赋值o.children
,这是必要的,因为o.children.filter
返回数组的新副本。赋值完成后,表达式解析为 newo.children
并返回其length
属性。然后根据上述递归案例规则将该长度视为真/假。这相当于:
obj.children = obj.children.filter(child => iter(child));
return obj.children.length > 0;
如果我们返回数组本身,所有内容都将被视为真,因为空数组 ,[]
的计算结果为真。[].length
,另一方面,计算结果为假,这是期望的结果。
至于o.children.filter(iter)
,Array#filter
接受一个回调作为它的第一个参数,它可以是一个函数变量,例如iter
. 另一种选择是直接在参数列表中创建一个匿名函数;这通常是如何完成的。上面的版本添加了一个箭头包装器,但它显然是不必要的额外间接层,因为唯一的参数只是通过包装器传递。我们也可以在function
这里使用关键字;不管怎样,目标都是一样的,就是我们传入一个函数filter
来调用每个元素。
顺便说一句,该函数假定key
在嵌套对象的所有节点上设置array
并且obj[key].includes
已定义。显然,作者有一个非常具体的数据结构和目的,并且对过早地概括不感兴趣。
这是说明其操作的测试代码。玩弄它应该有助于您的理解。
const recursivelyFilter = (arr, key, searchString) => {
return arr.filter(function iter(obj) {
if (obj[key].includes(searchString)) {
return true;
}
if (obj.children) {
obj.children = obj.children.filter(child => iter(child));
return obj.children.length > 0;
}
return false;
});
};
const arr = [
{
foo: "bar",
children: [
{
foo: "baz",
children: [
{foo: "quux"},
{foo: "quuz"},
]
}
]
},
{
foo: "corge",
children: [
{foo: "quux"}
]
},
{
foo: "grault",
children: [{foo: "bar"}]
}
];
console.log(recursivelyFilter(arr, "foo", "quux"));
推荐阅读
- java - SimpleDateFormat 显示错误的当地时间
- javascript - AJAX 不传递硬编码数据
- node.js - 我试图从 mongodb atlas 获取数据
- python - 如何自动将 PPT 转换为 PDF?
- node.js - 我如何在两条消息之间添加间隔?
- python - 如何通过异步套接字发送列表
- xcode - 如何使用 Parse SDK 解决 XCode 12 构建错误?
- javascript - 通过 InnerHTML 调用外部 HTML 页面(没有 ajax 或 iframe)
- vue.js - Buefy - 通过自定义动态加载表中的字段
- javascript - 如何从桌面通知中覆盖或删除签名“electron.app.Electron”