Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can not call my recursion function in javascript/Polymer

I have a function that searches through a tree of folders and finds the selected folder's parent folder.

Here is the function.

        getParentFolder: function (searchroot, childFolder) {
            searchroot.subfolders.forEach(function (folder) {
                if (folder.key == childFolder.key) {
                    return searchroot;
                }
                else {
                    if (folder.subfolders) {
                        return this.getParentFolder(folder, childFolder);
                    }
                }
            });
        }

When I call this with this.getParentFolder(rootFolder, childFolder);

It simply just gives me: Uncaught TypeError: this.getParentFolder is not a function Why is this? In the same file I call other functions they work perfectly fine. This is the only function that I fail to be able to call. Is it because of the recursion?

like image 938
nanobots Avatar asked Aug 16 '17 15:08

nanobots


People also ask

How do you call a recursive function in JavaScript?

The syntax for recursive function is: function recurse() { // function code recurse(); // function code } recurse(); Here, the recurse() function is a recursive function. It is calling itself inside the function.

Can JavaScript support recursion?

Recursion is a programming pattern or concept embedded in many programming languages, and JavaScript is not left out. It is a feature used in creating a function that keeps calling itself but with a smaller input every consecutive time until the code's desired result from the start is achieved.


2 Answers

You have to keep this in a variable as you change your context inside the forEach method.

getParentFolder: function(searchroot, childFolder) {
  var self = this;
  searchroot.subfolders.forEach(function(folder) {
    if (folder.key == childFolder.key) {
      return searchroot;
    } else {
      if (folder.subfolders) {
        return self.getParentFolder(folder, childFolder);
      }
    }
  });
}

Also, return statement won't work the way you want. I recommend you to enumerate the array using a for loop :

getParentFolder: function(searchroot, childFolder) {
  for (var i = 0; i < searchroot.subfolders.length; i++) {
    var folder = searchroot.subfolders[i];
    if (folder.key == childFolder.key) {
      return searchroot;
    } else {
      if (folder.subfolders) {
        return self.getParentFolder(folder, childFolder);
      }
    }
  }
}
like image 99
Serge K. Avatar answered Oct 20 '22 22:10

Serge K.


The problem is that your this is different inside of function you passed into the forEach. You need to bind the outer this to the inner function:

getParentFolder: function(searchroot, childFolder) {
  searchroot.subfolders.forEach(function(folder) {
    if (folder.key == childFolder.key) {
      return searchroot;
    } else {
      if (folder.subfolders) {
        return this.getParentFolder(folder, childFolder);
      }
   }
  }, this); // pass in outer this as context for inner function
}

From Array.prototype.forEach() on MDN:

Syntax:

arr.forEach(function callback(currentValue, index, array) {
   //your iterator
}[, thisArg]);

Alternative Solution using ES6:

As mishu mentioned in the comments, the new ES6 arrow syntax also solves this problem. Your code in ES6 would look something like this:

getParentFolder: function(searchroot, childFolder) {
  searchroot.subfolders.forEach((folder) => {
    if (folder.key == childFolder.key) {
      return searchroot;
    } else {
      if (folder.subfolders) {
        return this.getParentFolder(folder, childFolder);
      }
    }
  });
}

Arrow functions is ES6 do not bind this (see MDN) so the outer this can be accessed from within the arrow function.

Note that not all browsers support arrow functions yet (see Browser compatibility on MDN). To support older browsers, you can transpile ES6 to ES5 using Babel.

like image 3
Sumner Evans Avatar answered Oct 20 '22 21:10

Sumner Evans