Javascript 使用for循环在对象数组上递归循环
TLDR如果我有一个包含对象的数组,而其中一些对象是包含更多对象的数组,我如何递归地循环这些对象并返回其中一个嵌套值?在下面的代码中,使用return只解析第一个元素。如果我不使用return,该值将丢失,因为它在一个递归作用域中被销毁Javascript 使用for循环在对象数组上递归循环,javascript,vue.js,vuex,Javascript,Vue.js,Vuex,TLDR如果我有一个包含对象的数组,而其中一些对象是包含更多对象的数组,我如何递归地循环这些对象并返回其中一个嵌套值?在下面的代码中,使用return只解析第一个元素。如果我不使用return,该值将丢失,因为它在一个递归作用域中被销毁 var currentNode = [{...}, {...}, { items: [{...}, {...}] }] // If it's not found, looping through the children (there should b
var currentNode = [{...}, {...}, { items: [{...}, {...}] }]
// If it's not found, looping through the children (there should be more wrapper nodes in the children)
for (let node of currentNode) {
if (node.uuid === uuidToFind) {
return node;
}
// THIS CAN'T LOOP
// BUT there's a lexical scoping problem if I don't use `return`
return searchTreeForNode(node, nodeUuidToFind);
}
}
更长的摘要:
我目前正在处理一个树状结构,它当前保存在Vuex状态
在我开始讨论这个问题之前,我有两个问题:
中)的词法作用域方面遇到了问题
但让我先描述一下这棵树,它有两种不同的节点
一个单个节点
,如下所示:
{
name: `string`
value: `string`
}
{
type: `string`,
children: [
{},
{},
...
]
}
currentNode.forEach( singleNode => {
evalueateChildNodes(singleNode);
});
evaluateChildNodes(node) {
// You can check the id here and assign it to some variable if necessary
// Or if you found your specific node, you can push a new node to its children etc.
// Note that even though the function name is 'evaluateChildNodes',
// it will touch all root nodes due to the forEach() above.
if (node.children) {
evaluateChildNodes(node.children);
}
}
和包装节点
。包装节点
中的子节点可以是单个节点
或包装节点
其结构如下所示:
{
name: `string`
value: `string`
}
{
type: `string`,
children: [
{},
{},
...
]
}
currentNode.forEach( singleNode => {
evalueateChildNodes(singleNode);
});
evaluateChildNodes(node) {
// You can check the id here and assign it to some variable if necessary
// Or if you found your specific node, you can push a new node to its children etc.
// Note that even though the function name is 'evaluateChildNodes',
// it will touch all root nodes due to the forEach() above.
if (node.children) {
evaluateChildNodes(node.children);
}
}
这些节点也可以嵌套无限次
下面是一个示例对象:
{
type: `level 1`,
children: [
{
type: `level 2`,
children: [
{
type: `level 3`,
children: []
},
{
name: `item 1`,
value: `value 1`
},
{
name: `item 2`,
value: `value 2`
},
...
]
},
{
name: `item 1`,
value: `value 1`
},
{
type: `level 2.1`,
children: [
{
name: `item 3`,
value: `value 3`
}
...
]
}
...
]
}
使用此树,我希望能够在树中的任何位置添加单个节点
和包装节点
,但我在这方面遇到了困难
我最初的尝试涉及遍历每个节点并为其分配一个UUID。计划是在树中循环,当我找到匹配的UUID时,我可以根据需要对其进行操作
这就是该尝试的代码:
// This starts with the top-level wrapper node
function searchTreeForNode(currentNode, nodeUuidToFind) {
if (currentNode.uuid === nodeUuidToFind) {
return currentNode;
}
// If it's a wrapper node, parse the children
if (currentNode.hasOwnProperty("type")) {
return searchTreeForNode(currentNode.children, nodeUuidToFind);
}
// If it's the contents of a wrapper node, see if that node lives in them
if (Array.isArray(currentNode)) {
let resolvedUuids = [];
for (let node of currentNode) {
resolvedUuids.push(node.uuid);
}
// If found, return the node
let uuidLocation = resolvedUuids.indexOf(nodeUuidToFind);
if (uuidLocation !== -1) {
return currentNode[uuidLocation];
}
// If it's not found, looping through the children (there should be more wrapper nodes in the children)
for (let node of currentNode) {
// THIS CAN'T LOOP
// BUT there's a lexical scoping problem if I don't use `return`
return searchTreeForNode(node, nodeUuidToFind);
}
}
}
是否有可能使上述代码正常工作?特别是通过包装器节点的子节点进行循环
如果不是的话,我现在的想法是,不要把树放在州里,而是有三样东西
nodeTree
-与原始数据具有相同形状的对象,但每个节点只是一个UUID
AllRuleUUID
-字符串数组。每个字符串都是节点的UUID
nodeDataByUuid
-在allRuleUuids
数组中键入UUID的对象。每个对象将包含每个节点的数据
我需要支持的行为如下:
- 在树中的任意位置添加
单个节点
和包装节点
- 从树的任何部分删除
单个节点
和包装节点
(包括其所有子节点)
提前感谢您的帮助!我想您需要这样的帮助:
{
name: `string`
value: `string`
}
{
type: `string`,
children: [
{},
{},
...
]
}
currentNode.forEach( singleNode => {
evalueateChildNodes(singleNode);
});
evaluateChildNodes(node) {
// You can check the id here and assign it to some variable if necessary
// Or if you found your specific node, you can push a new node to its children etc.
// Note that even though the function name is 'evaluateChildNodes',
// it will touch all root nodes due to the forEach() above.
if (node.children) {
evaluateChildNodes(node.children);
}
}
此代码将递归地遍历整个树并触摸每个节点
或者,您可以将上述内容分配给一个变量,并在找到合适的内容时返回节点。我认为您需要这样的内容:
{
name: `string`
value: `string`
}
{
type: `string`,
children: [
{},
{},
...
]
}
currentNode.forEach( singleNode => {
evalueateChildNodes(singleNode);
});
evaluateChildNodes(node) {
// You can check the id here and assign it to some variable if necessary
// Or if you found your specific node, you can push a new node to its children etc.
// Note that even though the function name is 'evaluateChildNodes',
// it will touch all root nodes due to the forEach() above.
if (node.children) {
evaluateChildNodes(node.children);
}
}
此代码将递归地遍历整个树并触摸每个节点
或者,您可以将上述内容分配给一个变量,并在找到合适的内容时返回节点。您可以使用索引数组来表示节点的路径,如:
[0, 1, 4]
好的,这是一个过于简化的实现
function getNode(tree, path) {
let current = tree;
// find node
for (let i = 0; i < path.length; i++) {
current = current.children[path[i]];
}
return current;
}
function addNode(tree, path, node) {
const index = path.pop();
// ^ careful, this mutates the original array
// you can clone it if you wish
// or use string paths like `0/1/4`
// and use path.split('/') to get the indexes
const parent = getNode(tree, path);
parent.children[index] = node;
}
function deleteNode(tree, path) {
const index = path.pop();
const parent = getNode(tree, path);
delete parent.children[index];
}
// you can get nodes like this
console.log(getNode(tree, [1]));
// and add nodes like this
addNode(tree, [0, 3], { name: 'test', value: 'test' });
// you can get the root node like this
console.log(getNode(tree, []));
函数getNode(树,路径){
让当前=树;
//查找节点
for(设i=0;i
我没有处理过给定错误路径的情况,即假设路径
[0,1,4]
中的所有索引都引用包装器节点,但最后一个索引除外。但是您知道了。您可以使用一个索引数组来表示节点的路径,如:
[0, 1, 4]
好的,这是一个过于简化的实现
function getNode(tree, path) {
let current = tree;
// find node
for (let i = 0; i < path.length; i++) {
current = current.children[path[i]];
}
return current;
}
function addNode(tree, path, node) {
const index = path.pop();
// ^ careful, this mutates the original array
// you can clone it if you wish
// or use string paths like `0/1/4`
// and use path.split('/') to get the indexes
const parent = getNode(tree, path);
parent.children[index] = node;
}
function deleteNode(tree, path) {
const index = path.pop();
const parent = getNode(tree, path);
delete parent.children[index];
}
// you can get nodes like this
console.log(getNode(tree, [1]));
// and add nodes like this
addNode(tree, [0, 3], { name: 'test', value: 'test' });
// you can get the root node like this
console.log(getNode(tree, []));
函数getNode(树,路径){
让当前=树;
//查找节点
for(设i=0;i我没有处理给出错误路径的情况,也就是说,假设路径中的所有索引都引用包装器节点,但最后一个索引除外。但是你明白了。我更改了你的代码。这样就可以了 一个更干净的选择是将结构展平,然后进行简单的查找。
const flattenTree = node =>
node.children
? [node, ...node.children.flatMap(flattenTree)]
: [node];
然后,发现变得简单:
flattenTree(sampleTree).find(node=>node.uuid === 'item5');
我更改了你的代码。这样就可以了