无法在javascript/Polymer中调用我的递归函数

5

我有一个函数,它可以搜索文件夹树并找到所选文件夹的父文件夹。

以下是该函数。

        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.getParentFolder(rootFolder, childFolder); 调用时, 它只是给了我一个错误:Uncaught TypeError: this.getParentFolder is not a function。 为什么会这样?在同一个文件中,我调用其他函数都能正常工作。这是唯一一个我无法调用的函数。难道是因为递归吗?
2个回答

5

forEach 方法中改变上下文时,你需要将 this 保存在一个变量中。

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);
      }
    }
  });
}

此外,return语句不会按照你的期望工作。建议使用for循环枚举数组:
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);
      }
    }
  }
}

1
当然,如果你想跟踪你的主要对象,你可以使用 bind - Serge K.
1
@nanobots,你可以将外部的 this 作为参数传递给 forEach,这样就避免了使用 self - Sumner Evans
@SumnerEvans 忘记了这个 :) - Serge K.
2
我明白了,因为foreach(function())创建的temp函数改变了this的上下文,所以我遇到了这个问题,是这样吗? - nanobots
1
@nanobots,没错。 - Sumner Evans
显示剩余4条评论

3

问题在于你在传递给forEach的函数内部,this的值与外部不同。你需要将外部的this与内部函数绑定:

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
}

来自 MDN 上的 Array.prototype.forEach()

Syntax:

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

使用ES6的替代方案:

正如 mishu 在评论中提到的,新的ES6箭头语法也可以解决这个问题。在ES6中,您的代码将类似于以下内容:

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

ES6中的箭头函数不会绑定this(参见MDN),因此外部的this可以从箭头函数内部访问。
请注意,并非所有浏览器都支持箭头函数(参见MDN上的浏览器兼容性)。为了支持旧版浏览器,您可以使用Babel将ES6转译为ES5。

2
新的ES6箭头语法也不会绑定this,这样不是也解决了这个问题吗?https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_binding_of_this - mishu
1
@mishu,是的,我更新了我的答案并包含了那个。好建议! - Sumner Evans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接