Recursion troubles with "return undefined" (JavaScript)

I'm stuck with recursion. I've read a few similar questions, but it brought me no relief. My function works well inside, but it returns "undefined" at the end.

I have a binary tree. Now I'm trying to make a function, which can get me an answer: if any nodes on this level have children.

class tree_node {
    constructor(n_array, parent) {
        this.n_array = n_array;
        this.has_children = false;
        this.children = [];
        if (parent != null) {
            this.parent = parent;
            this.level = this.parent.level + 1;
        }
        else {
            this.level = 0;
        }
        // run the tree
        this.child();
    }
    child() {
        if (this.n_array.length != 1) {
            this.has_children = true;
            let m = Math.floor(this.n_array.length / 2);
            let l = this.n_array.slice(0, m);
            let r = this.n_array.slice(m);
            const left = new tree_node(l, this);
            const right = new tree_node(r, this);
            this.children.push(left, right);
        }
        else return 0
    }

    get_if_node_has_children(node, level) {
        console.log(node.level, node.has_children)
        if (node.has_children && node.level < level) {
            console.log("in loop")
            node.children.forEach(element => {
                return element.get_if_node_has_children(element, level);
            });
        }
        else {
            console.log("first else")
            if (node.level == level && node.has_children) {
                console.log("node.level == level && node.has_children " + node.n_array)
                return true;
            }
            else {
                console.log("return false")
                return false;
            }
        }
    }
    show() {
        console.log(this.n_array + " | Level: " + this.level + ". " + this.branch + " Has children = " + this.has_children);
        if (this.has_children) {
            this.children.forEach(element => {
                return element.show();
            });
        }
        else {
            return 0;
        }
    }    
}

get_if_node_has_children(node, level) work inside, so to speak. I've expected the exact behaviour and log. Except on thing: function returns "undefined". But I have no idea where I missed the point.

let root = [];

class tree_node {
  constructor(n_array, parent) {
    this.n_array = n_array;
    this.has_children = false;
    this.children = [];
    // при создании экземпляра класса то parent == null
    if (parent != null) {
      this.parent = parent;
      this.level = this.parent.level + 1;
    } else {
      this.level = 0;
    }
    // run the tree
    this.child();
  }
  child() {
    if (this.n_array.length != 1) {
      this.has_children = true;
      let m = Math.floor(this.n_array.length / 2);
      let l = this.n_array.slice(0, m);
      let r = this.n_array.slice(m);
      const left = new tree_node(l, this);
      const right = new tree_node(r, this);
      this.children.push(left, right);
    } else return 0
  }

  get_if_node_has_children(node, level) {
    console.log(node.level, node.has_children)

    if (node.has_children && node.level < level) {
      console.log("in loop")
      node.children.forEach(element => {
        return element.get_if_node_has_children(element, level);
      });
    } else {
      console.log("first else")
      if (node.level == level && node.has_children) {
        console.log("node.level == level && node.has_children " + node.n_array)
        return true;
      } else {
        console.log("return false")
        return false;
      }
    }
  }

  show() {
    console.log(this.n_array + " | Level: " + this.level + ". " + "Has children = " + this.has_children);
    if (this.has_children) {
      this.children.forEach(element => {
        return element.show();
      });
    } else {
      return 0;
    }
  }
  // CLASS END ===========================
}

root = new tree_node([1, 3, 5, 7, 9, ])
console.log("=== root.show() ===")
root.show();
console.log("=== let a = root.get_if_node_has_children(root, 2) ===")
let a = root.get_if_node_has_children(root, 2)
console.log(" a is " + a)

There are two problems:

  1. return inside a callback (for instance, your forEach callback) just returns from the callback, not the function that called forEach. In general, in modern code, use for-of unless you need the index of the element.

  2. You're not checking the result of the recursive call before returning it. But if the first child node you call it on returns false, you want to keep looking, rather than immediately returning false.

Fixing both:

get_if_node_has_children(node, level) {
    console.log(node.level, node.has_children)
    if (node.has_children && node.level < level) {
        console.log("in loop")
        for (const element of node.children) { // *** #1, using `for-of` instead of `forEach` so we can return below
            const hasChild = element.get_if_node_has_children(element, level);
            if (hasChild) {     // *** #2, only return here if you got `true`
                return true;    // *** 
            }                   // *** 
        }
        return false; // *** #2 part 2 -- didn't find it anywhere, return `false`
    } else {
        console.log("first else")
        if (node.level == level && node.has_children) {
            console.log("node.level == level && node.has_children " + node.n_array)
            return true;
        } else {
            console.log("return false")
            return false;
        }
    }
}

I'd reorganize that slightly though, which is easier if I remove some no-longer-needed logging:

get_if_node_has_children(node, level) {
    console.log(node.level, node.has_children)
    if (node.has_children) {
        if (node.level === level) {
            return true;
        }
        if (node.level < level) {
            for (const element of node.children) {
                if (element.get_if_node_has_children(element, level)) {
                    return true;
                }
            }
        }
    }
    return false;
}