javascript - 无法递归删除对象数组中的对象
问题描述
const arr = [
{
id: "8bfc-2b82-68ad-fb78",
name: "inventory",
type: "directory",
path: "inventory/",
children: [
{
id: "bccf-3788-6ec9-ba33",
name: "inventory.yaml",
type: "file",
path: "inventory/inventory.yaml",
},
],
},
{
id: "4a28-4d63-6c30-4569",
name: "model",
type: "directory",
path: "model/",
children: [
{
id: "21d1-f4d2-e1c5-34b0",
name: "model.yaml",
type: "file",
path: "model/model.yaml",
},
],
},
];
function _worktreeItemDelete({ detail }) {
const currentId = detail.item.id;
const filtered = this.tree.filter(entry => entry.id !== currentId);
const updTree = filtered.map(entry => {
if (!entry.children) return entry;
return {...entry, children: this._worktreeItemDelete(entry.children, currentId)};
});
console.log(updTree);
this.set("tree", updTree);
}
这就是我正在做的。currentId
我正在捕捉作为事件属性值。我现在遇到的问题是:
Uncaught RangeError: Maximum call stack size exceeded
如果我理解正确,递归并没有停止,正在寻找一种方法来处理这个问题。感谢你的帮助。
解决方案
修复功能
你很近。问题是您将一个对象传递给初始删除调用,提取嵌套属性id
以正确使用,但是当您进行递归调用时,您只使用该 id,而不是整个对象。
最快的解决方法可能是保留对该对象的引用,而不是在参数中对其进行解构。我对上下文没有足够的理解来恰当地命名它,所以我就叫它foo
。然后我们可以传递foo
给递归调用,它就可以工作了。
通过该修复,您的函数的变体将正常工作:
function _worktreeItemDelete(tree, foo) {
const currentId = foo.detail.item.id;
const filtered = tree.filter(entry => entry.id !== currentId);
const updTree = filtered.map(entry => {
if (!entry.children) return entry;
return {...entry, children: _worktreeItemDelete(entry.children, foo)};
});
return updTree
}
const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]
console .log (
_worktreeItemDelete (arr, {detail: {item: {id: 'bccf-3788-6ec9-ba33'}}})
)
.as-console-wrapper {max-height: 100% !important; top: 0}
请注意,我将其更改为纯函数而不是方法,因此跳过this.set("tree", updTree)
、添加tree
参数和删除this
引用。它们应该很容易放回去。
但是,上面并没有解释你描述的递归深度错误。我会期待更多类似的东西
Cannot read property 'item' of undefined
所以可能会发生一些额外的事情。
另一种方法
我会以不同的方式编写此代码。我会使用一个通用版本的树过滤函数,并将它传递给节点选择的谓词。
我的版本可能如下所示:
const deepFilter = (pred) => (xs) =>
xs .flatMap (({children = [], ...rest}) =>
pred (rest)
? [{... rest, children: deepFilter (pred) (children)}]
: []
)
const removeById = ({detail: {item: {id: target}}}) =>
deepFilter (({id}) => id !== target)
const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]
console .log (
removeById ({detail: {item: {id: 'bccf-3788-6ec9-ba33'}}}) (arr)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
请注意,这deepFilter
是通用的。它适用于后代节点位于属性中的任何树children
。(有关可让您配置此属性的更通用版本,请参阅另一个答案。)
所以这里的自定义代码就是removeById
. 在我看来,这是一场不错的胜利。
如果它很重要,我们可以——以额外的复杂性为代价——选择仅children
在数据不为空时包含节点。如果您想要它并需要帮助,只需添加评论即可。
推荐阅读
- python - Python - 编辑文本以仅在给定文本中保留来自 URL 的域名
- github - GitHub Actions 在错误的分支上运行工作流
- javascript - Jquery点击功能不适用于所有ID
- javascript - 在 React 中使用 useState 在 Promise 中设置状态时,应用程序会不断重新渲染
- python - 烧瓶:烧瓶运行在 conda 环境中不起作用 - Windows、Python 3.8 和 conda 4.7.12
- java - 具有两个 AtomicInteger 的线程安全方法是否可能?
- emacs - 更改 Org-mode Mind-Map 中的节点属性
- google-app-engine - App Engine Gen 2 Go 1.12 - 从 Go 1.9 Gen1 迁移后的超时
- python - 使目录在不同计算机上通用(相对?)的方法?
- c# - C# 将生成的点转换为图形