Я написал рекурсивную функцию, но она возвращает только одного дочернего элемента, как я могу заставить ее вернуть всех дочерних элементов?

#javascript

#javascript

Вопрос:

У меня есть массив объектов, которые представляют структуру разметки HTML-страницы. Я написал рекурсивную функцию, которая частично работает, но не может понять, как вернуть более одного дочернего объекта из объекта, имеющего более одного дочернего объекта.

Вот массив объектов:

 const arrayOfObjects = [
  {"type": "Root", "id":0, "children" : [
    {"type" : "Title", "id": "foo"},
    {"type" : "Image", "id": "bar"},
    {"type" : "Container", "id": "blo", "children":[ 
      {"type" : "Container", "id": "goo", "children":[
        {"type" : "Image", "id": "tar"},
        {"type" : "Video", "id": "yar"}
      ]},
      {"type" : "Container", "id": "sha", "children":[ 
        {"type" : "Title", "id": "koo"},
      ]},
    ]},
    {"type" : "Container", "id": "boo", "children":[
      {"type" : "Container", "id": "bos", "children":[
        {"type" : "Container", "id": "ooo", "children":[
          {"type" : "Container", "id": "loo", "children":[
            {"type" : "Title", "id": "bar"},
            {"type" : "Image", "id": "rab"}
          ]}
        ]}
      ]}
    ]}
  ]}
 ]
 

Вот мой код:

     const findChildren = (el) => {
      let x = []
      if(el.type === "Container"){
        x  = '['   el.type   ']' 
          findChildren(el.children[0]) 
          '[/'   el.type   ']'
        return x 
      }
      else{ 
       return x  = '['   el.type   '/]'
      }
    }

    genStructure = (data) => {
      let output = []
      data.forEach(function(el) {
        output  = findChildren(el)
      });
      return output
    }

    genStructure(arrayOfObjects[0].children) // here I ignore root as it will always be the same
 

Это то, что я получаю, когда запускаю его.

 [Title/][Image/][Container][Container][Image/][/Container][/Container][Container][Container][Container][Container][Title/][/Container][/Container][/Container][/Container]
 

Но это то, что мне нужно, когда я его запускаю. Как вы можете видеть, в нем отсутствует контейнер с заголовком (идентификатор sha для контейнера и koo для заголовка) и отсутствует заголовок (идентификатор rab )

 [Title/][Image/][Container][Container][Image/][Video/][/Container][Container][Title/][/Container][/Container][Container][Container][Container][Container][Title/][Image/][/Container][/Container][/Container][/Container]
 

Я чувствую, что, возможно, я близок, но я не могу понять, что я делаю не так. Как я могу получить недостающие данные?

Вот jsfiddle этого https://jsfiddle.net/gwxhymq4/5 /

Комментарии:

1. прежде всего, если output это массив, вы не можете добавлять к нему элементы с помощью . Вам нужно будет использовать output.push(/*...*/)

2. @DanielCheung Технически вы можете — пустой массив будет преобразован в строку, в результате чего пустая строка будет объединена с выражением справа — но наличие массива в первую очередь не имеет никакого смысла, да.

3. @CertainPerformance да, я понимаю. Вот почему я называю это «добавлением элементов». Но та же мысль, это не имеет смысла.

Ответ №1:

Вместо findChildren(el.children[0]) этого вы должны использовать .map для перебора всех дочерних элементов и получения результирующей строки (а не только первого дочернего элемента):

   el.children.map(findChildren).join('')
 

или вызовите genStructure снова, который использует ту же логику.

Кроме того, было бы более уместно либо инициализировать x пустую строку, либо оставить ее полностью и только return выражения внутри if / else :

 const arrayOfObjects = [
  {"type": "Root", "id":0, "children" : [
    {"type" : "Title", "id": "foo"},
    {"type" : "Image", "id": "bar"},
    {"type" : "Container", "id": "blo", "children":[ 
      {"type" : "Container", "id": "goo", "children":[
        {"type" : "Image", "id": "tar"},
        {"type" : "Video", "id": "yar"}
      ]},
      {"type" : "Container", "id": "sha", "children":[ 
        {"type" : "Title", "id": "koo"},
      ]},
    ]},
    {"type" : "Container", "id": "boo", "children":[
      {"type" : "Container", "id": "bos", "children":[
        {"type" : "Container", "id": "ooo", "children":[
          {"type" : "Container", "id": "loo", "children":[
            {"type" : "Title", "id": "bar"},
            {"type" : "Image", "id": "rab"}
          ]}
        ]}
      ]}
    ]}
  ]}
 ]
const findChildren = (el) => {
  if(el.type === "Container"){
    return (
      '[Container]' 
        mapChildren(el)
        '[/Container]'
    );
  } else{ 
   return '['   el.type   '/]'
  }
};

const mapChildren = (element) => {
  return element.children.map(findChildren).join('');
}

console.log(mapChildren(arrayOfObjects[0])); 

Комментарии:

1. Вместо el.children.map(findChildren).join('') этого я бы рекомендовал вызвать genStructure(el.children) , который OP подготовил именно для этой цели. (Конечно, его реализация должна быть исправлена или упрощена до того, что у вас есть)

Ответ №2:

 const findChildren = (el) => {
  let x = '';
  if(el.type === "Container"){
    el.children.forEach(function(child) {
        x  = findChildren(child)
    });
    return '['   el.type   ']'   x   '[/'   el.type   ']';
  }
  else{ 
   return '['   el.type   '/]'
  }
}
 

Ответ №3:

Это HTML-код.

 <div id='meh'>

</div>
 

И это код JavaScript.

 const arrayOfObjects = [
  {"type": "Root", "id":0, "children" : [
    {"type" : "Title", "id": "foo"},
    {"type" : "Image", "id": "bar"},
    {"type" : "Container", "id": "blo", "children":[ 
      {"type" : "Container", "id": "goo", "children":[
        {"type" : "Image", "id": "tar"},
        {"type" : "Video", "id": "yar"}
      ]},
      {"type" : "Container", "id": "sha", "children":[ 
        {"type" : "Title", "id": "koo"},
      ]},
    ]},
    {"type" : "Container", "id": "boo", "children":[
      {"type" : "Container", "id": "bos", "children":[
        {"type" : "Container", "id": "ooo", "children":[
          {"type" : "Container", "id": "loo", "children":[
            {"type" : "Title", "id": "bar"},
            {"type" : "Image", "id": "rab"}
          ]}
        ]}
      ]}
    ] }
  ]}
]

const findChildren = (el) => {
        let x = []
        if(el.type === "Container"){

      x  = '['   el.type   ']';
      el.children.forEach(e => {
        x  = findChildren(e)
      });
      x  = '[/'   el.type   ']';
      return x 
        }
    else{ 
      return x  = '['   el.type   '/]'
    }
}
  
genStructure = (data) => {
  let output = []
  data.forEach(function(el) {
   output  = findChildren(el)
});
  return output
}


const el = document.getElementById("meh")
el.innerHTML = genStructure(arrayOfObjects[0].children)
 

И это результат.

 [Title/][Image/][Container][Container][Image/][Video/][/Container][Container][Title/][/Container][/Container][Container][Container][Container][Container][Title/][Image/][/Container][/Container][/Container][/Container]