Javascript 重构代码到尾部递归

Javascript 重构代码到尾部递归,javascript,recursion,stack,tail-recursion,Javascript,Recursion,Stack,Tail Recursion,我有一个函数,它通过“节点”,这些节点有一个键和它们自己的节点数组。我还有一个允许的密钥数组。目标很简单:如果一个节点有一个允许的密钥,或者一个子节点有一个允许的密钥,则保留它,否则,删除它。当前的解决方案如下所示: var allowedKeys=['x','y','z']; 变量节点=[{ 键:“x”, 节点:[] }, { 键:“b”, 节点:[{ 键:“y”, 节点:[] }, { 键:“lol”, 节点:[] }, ] }, { 键:“c” }, { 键:“d”, 节点:[] },

我有一个函数,它通过“节点”,这些节点有一个键和它们自己的
节点
数组。我还有一个允许的密钥数组。目标很简单:如果一个节点有一个允许的密钥,或者一个子节点有一个允许的密钥,则保留它,否则,删除它。当前的解决方案如下所示:

var allowedKeys=['x','y','z'];
变量节点=[{
键:“x”,
节点:[]
},
{
键:“b”,
节点:[{
键:“y”,
节点:[]
},
{
键:“lol”,
节点:[]
},
]
},
{
键:“c”
},
{
键:“d”,
节点:[]
},
{
键:“e”,
节点:[{
键:“t”,
节点:[{
键:“z”,
节点:[]
}]
},
{
键:“r”,
节点:[]
},
]
},
{
键:“f”,
节点:[]
}
];
函数hasChildNodes(节点){
var hasChildNodes=node.hasOwnProperty('nodes')&&node.nodes.length>0;
返回hasChildNodes;
}
函数移除不必要的节点(节点、AllowedKey){
nodes.forEach(node=>{
if(hasChildNodes(节点)){
node.nodes=移除不必要的节点(node.nodes,AllowedKey);
}
});
nodes=nodes.filter(node=>allowedkey.includes(node.key)| | hasChildNodes(node));
返回节点;
}
var filteredNodes=移除不必要的节点(节点、AllowedKey);

控制台日志(过滤节点)继我的评论之后,我想尝试一个堆栈版本。它不像我希望的那么干净,但我想无论如何我都会把它贴出来,希望它能在某种程度上发光

var节点=[{
键:“x”,
节点:[]
},
{
键:“b”,
节点:[{
键:“y”,
节点:[]
},
{
键:“lol”,
节点:[]
},
]
},
{
键:“c”
},
{
键:“d”,
节点:[]
},
{
键:“e”,
节点:[{
键:“t”,
节点:[{
键:“z”,
节点:[]
}]
},
{
键:“r”,
节点:[]
},
]
},
{
键:“f”,
节点:[]
}
];
var allowedKeys=['x','y','z'];
常量removeUnnecessaryNodes=(节点,allowedKeys)=>{
const allowed=新集合(allowedkey);
const root={nodes:nodes};
常量堆栈=[root];
while(堆栈长度){
让curr=stack.pop();
if(curr.nodes&&curr.nodes.length){
//非空节点,在堆栈上推送子节点
curr.nodes.forEach(e=>{
e、 父项=当前值;
栈推(e);
});
}
否则,如果(!allowed.has(curr.key)){
//这是一片不允许的叶子;请将其移除
设p=curr.parent;
如果(p){
p、 nodes=p.nodes.filter(e=>e!==curr);//O(n)
}
//向上移动结构,修剪死去的祖先
while(p&&!p.nodes.length&&!allowed.has(p.key)){
curr=p;
p=当前父项;
如果(p){
p、 nodes=p.nodes.filter(e=>e!==curr);//O(n)
}
}
}
}
//清理临时父密钥
栈.推(根);
while(堆栈长度){
const curr=stack.pop();
if(当前节点){
curr.nodes.forEach(e=>{
删除e.parent;
栈推(e);
});
}
}
返回root.nodes;
};
var filteredNodes=移除不必要的节点(节点、AllowedKey);

log(JSON.stringify(filteredNodes,null,4))
您可以转换为使用
async
代码,即使您没有任何异步方法,
async
的一个优点是调用堆栈可以在递归过程中清除。可以重新编写调用堆栈以使用显式堆栈模拟递归。