Skip to content
Advertisement

Javascript recursive with for loop breaks the loop and does not finishes

I am writing a recursive function that needs to run in an array of objects with any level of deepness. (if it finds an array it will run into this array after finishing the object properties)

The idea is to create a generic table in a webpage that can handle any king of object structure and rendering elements respecting their hierarchy.

I can go any level deeper but it never finishes the loop:

let keys = [
  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'filhos', 'netos', 'bisnetos'
];

let tempArr = [];
let counter = 0;

function renderer(arr) {
  for (let x = 0; x < arr.length; x++) {
    const currItem = arr[x];

    for (let y = 0; y < keys.length; y++) {
      const inner = currItem[keys[y]]
      if (inner instanceof Array) {
        tempArr = inner;
      }
      if (inner && !(inner instanceof Array)) {
        console.log(`renderizando ${counter} camada: `, inner);
      }

      if (y === keys.length - 1) {
        if (tempArr.length > 0) {
          const children = tempArr;
          tempArr = [];
          return renderer(children);
        } else {
          continue;
        }
      }
    }
  }

  counter++;
  console.log('counter: ', counter);
  return counter;
}

const data = [{
    a: '1st item',
    b: '2nd item',
    c: '3rd item',
    d: '4th item',
    filhos: [{
      a: 'filho 1st item',
      b: 'filho 2nd item',
      c: 'filho 3rd item',
      d: 'filho 4th item',
      netos: [{
        a: 'neto 1st item',
        b: 'neto 2nd item',
        c: 'neto 3rd item',
        d: 'neto 4th item',
        bisnetos: [{
          a: 'bisneto 1st item',
          b: 'bisneto 2nd item',
          c: 'bisneto 3rd item',
          d: 'bisneto 4th item',
          f: 'bisneto 5th item',
          g: 'bisneto 6th item',
          h: 'bisneto last item'
        }],
        f: 'neto 5th item',
        g: 'neto 6th item',
        h: 'neto last item'
      }],
      f: 'filho 5th item',
      g: 'filho 6th item',
      h: 'filho last item'
    }],
    f: '5th item',
    g: '6th item',
    h: 'last item'
  },
  {
    a: '1st item',
    b: '2nd item',
    c: '3rd item',
    d: '4th item',
    filhos: [{
      a: 'filho 1st item',
      b: 'filho 2nd item',
      c: 'filho 3rd item',
      d: 'filho 4th item',
      netos: [{
        a: 'neto 1st item',
        b: 'neto 2nd item',
        c: 'neto 3rd item',
        d: 'neto 4th item',
        bisnetos: [{
          a: 'bisneto 1st item',
          b: 'bisneto 2nd item',
          c: 'bisneto 3rd item',
          d: 'bisneto 4th item',
          f: 'bisneto 5th item',
          g: 'bisneto 6th item',
          h: 'bisneto last item'
        }],
        f: 'neto 5th item',
        g: 'neto 6th item',
        h: 'neto last item'
      }],
      f: 'filho 5th item',
      g: 'filho 6th item',
      h: 'filho last item'
    }],
    f: '5th item',
    g: '6th item',
    h: 'last item'
  },
  {
    a: '1st item',
    b: '2nd item',
    c: '3rd item',
    d: '4th item',
    filhos: [{
      a: 'filho 1st item',
      b: 'filho 2nd item',
      c: 'filho 3rd item',
      d: 'filho 4th item',
      netos: [{
        a: 'neto 1st item',
        b: 'neto 2nd item',
        c: 'neto 3rd item',
        d: 'neto 4th item',
        bisnetos: [{
          a: 'bisneto 1st item',
          b: 'bisneto 2nd item',
          c: 'bisneto 3rd item',
          d: 'bisneto 4th item',
          f: 'bisneto 5th item',
          g: 'bisneto 6th item',
          h: 'bisneto last item'
        }],
        f: 'neto 5th item',
        g: 'neto 6th item',
        h: 'neto last item'
      }],
      f: 'filho 5th item',
      g: 'filho 6th item',
      h: 'filho last item'
    }],
    f: '5th item',
    g: '6th item',
    h: 'last item'
  },
]

renderer(data);

See that it ends up after the first iteration in the first list without running into the next two objects.

Any insights?

thanks.

Advertisement

Answer

You shouldn’t use return when making the recursive call.

Also, avoid using global variables in recursive functions, it makes them non-reentrant. If you need data to persist and update, pass it as parameters and return values. You can use default values for the initial values.

In my rewrite, I pass counter as a parameter, and then return the updated value, which the caller assigns back to its counter. Similarly, I pass tempArr as a parameter.

let keys = [
  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'filhos', 'netos', 'bisnetos'
];

function renderer(arr, counter = 0, tempArr = []) {
  for (let x = 0; x < arr.length; x++) {
    const currItem = arr[x];

    for (let y = 0; y < keys.length; y++) {
      const inner = currItem[keys[y]]
      if (inner instanceof Array) {
        tempArr = inner;
      }
      if (inner && !(inner instanceof Array)) {
        console.log(`renderizando ${counter} camada: `, inner);
      }

      if (y === keys.length - 1) {
        if (tempArr.length > 0) {
          counter = renderer(tempArr, counter, []);
        }
      }
    }
  }

  counter++;
  console.log('counter: ', counter);
  return counter;
}

const data = [{
    a: '1st item',
    b: '2nd item',
    c: '3rd item',
    d: '4th item',
    filhos: [{
      a: 'filho 1st item',
      b: 'filho 2nd item',
      c: 'filho 3rd item',
      d: 'filho 4th item',
      netos: [{
        a: 'neto 1st item',
        b: 'neto 2nd item',
        c: 'neto 3rd item',
        d: 'neto 4th item',
        bisnetos: [{
          a: 'bisneto 1st item',
          b: 'bisneto 2nd item',
          c: 'bisneto 3rd item',
          d: 'bisneto 4th item',
          f: 'bisneto 5th item',
          g: 'bisneto 6th item',
          h: 'bisneto last item'
        }],
        f: 'neto 5th item',
        g: 'neto 6th item',
        h: 'neto last item'
      }],
      f: 'filho 5th item',
      g: 'filho 6th item',
      h: 'filho last item'
    }],
    f: '5th item',
    g: '6th item',
    h: 'last item'
  },
  {
    a: '1st item',
    b: '2nd item',
    c: '3rd item',
    d: '4th item',
    filhos: [{
      a: 'filho 1st item',
      b: 'filho 2nd item',
      c: 'filho 3rd item',
      d: 'filho 4th item',
      netos: [{
        a: 'neto 1st item',
        b: 'neto 2nd item',
        c: 'neto 3rd item',
        d: 'neto 4th item',
        bisnetos: [{
          a: 'bisneto 1st item',
          b: 'bisneto 2nd item',
          c: 'bisneto 3rd item',
          d: 'bisneto 4th item',
          f: 'bisneto 5th item',
          g: 'bisneto 6th item',
          h: 'bisneto last item'
        }],
        f: 'neto 5th item',
        g: 'neto 6th item',
        h: 'neto last item'
      }],
      f: 'filho 5th item',
      g: 'filho 6th item',
      h: 'filho last item'
    }],
    f: '5th item',
    g: '6th item',
    h: 'last item'
  },
  {
    a: '1st item',
    b: '2nd item',
    c: '3rd item',
    d: '4th item',
    filhos: [{
      a: 'filho 1st item',
      b: 'filho 2nd item',
      c: 'filho 3rd item',
      d: 'filho 4th item',
      netos: [{
        a: 'neto 1st item',
        b: 'neto 2nd item',
        c: 'neto 3rd item',
        d: 'neto 4th item',
        bisnetos: [{
          a: 'bisneto 1st item',
          b: 'bisneto 2nd item',
          c: 'bisneto 3rd item',
          d: 'bisneto 4th item',
          f: 'bisneto 5th item',
          g: 'bisneto 6th item',
          h: 'bisneto last item'
        }],
        f: 'neto 5th item',
        g: 'neto 6th item',
        h: 'neto last item'
      }],
      f: 'filho 5th item',
      g: 'filho 6th item',
      h: 'filho last item'
    }],
    f: '5th item',
    g: '6th item',
    h: 'last item'
  },
]

renderer(data);
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement