Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/magento/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用for循环在对象数组上递归循环_Javascript_Vue.js_Vuex - Fatal编程技术网

Javascript 使用for循环在对象数组上递归循环

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

TLDR如果我有一个包含对象的数组,而其中一些对象是包含更多对象的数组,我如何递归地循环这些对象并返回其中一个嵌套值?在下面的代码中,使用return只解析第一个元素。如果我不使用return,该值将丢失,因为它在一个递归作用域中被销毁

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状态

在我开始讨论这个问题之前,我有两个问题:

  • 有没有办法解决我遇到的词汇范围界定问题
  • 如果不是,我的备选方案听起来如何
  • 另外,为了快速参考,我有一个JSFIDLE的副本

    在下面尝试的解决方案中,我在递归函数(特别是of循环的最后一个
    中)的词法作用域方面遇到了问题

    但让我先描述一下这棵树,它有两种不同的节点

    一个
    单个节点
    ,如下所示:

    {
        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');
    

    我更改了你的代码。这样就可以了