递归JavaScript在第一次传递后返回

Recursive JavaScript returning after first pass

本文关键字:返回 第一次 JavaScript 递归      更新时间:2023-09-26

我有下面的递归javascript函数,它在主干的子级上循环。rionette CollectionView有子级ItemViews,而ItemViews又是CollectionViews:

  findViewByCid: function(cid, children){
      var col = (arguments.length === 1) ? this.children : children;
      if(cid in col){
        return col[cid];
      }
      for(child in col){
        var grandChildren = col[child].children;
        if(cid in grandChildren){
          return grandChildren[cid];
        }
        if(grandChildren && (!jQuery.isEmptyObject(grandChildren))){
          return this.findViewByCid(cid, grandChildren);
        }
      }
    }

我这样称呼它:

var view=DocumentManager.Documents.treeRoot.findViewByCid(model.cid);

问题在于线路:

return this.findViewByCid(cid, grandChildren);

如果我有一个像这样的层次结构

c1
|_c2
  |_c3
|_c4
  |_c5

然后te return语句将导致函数在通过th3 c2节点后退出,并且永远不会到达c4等。

如果删除return语句,则会找到正确的子项,但返回null。

如何继续解析层次结构并返回值?

返回将退出您的函数

尝试将所有内容保存在var中,在最后返回,如果需要返回多个值,它可以是一个数组。(不要在for循环中声明vars!)

以下是建议

findViewByCid: function(cid, children){
  var willBeReturned=[];
  var grandChildren;
  var col = (arguments.length === 1) ? this.children : children;
  if(cid in col){
    willBeReturned[willBeReturned.length] = col[cid];
  }
  for(child in col){
    grandChildren = col[child].children;
    if(cid in grandChildren){
      willBeReturned[willBeReturned.length] = grandChildren[cid];
    }
    if(grandChildren && (!jQuery.isEmptyObject(grandChildren))){
      willBeReturned[willBeReturned.length] = this.findViewByCid(cid, grandChildren);
    }
  }
  return willBeReturned;
}

只有在找到内容时才需要返回,否则return语句将在不搜索其他子项的情况下中断循环。这是一个简单的深度优先搜索你想要什么。

假设函数在每个子节点的原型上(不仅在根节点上):

findViewByCid: function(cid) {
    var col = this.children;
    if (!col) // break if the node has no children
        return false;
    if (cid in col) // look for cid and return the node if one found
        return col[cid];
    for (var child in col) {
        // search through each child and return the result if something is found
        var found = col[child].findViewByCid(cid);
        if (found)
            return found;
    }
    // else nothing was found
    return false;
}

或者有一个以节点为自变量的函数:

function findViewByCid(cid, node) {
    var col = node.children;
    if (!col)
        return false;
    if (cid in col)
        return col[cid];
    for (var child in col) {
        var found = findViewByCid(cid, col[child]);
        if (found)
            return found;
    }
    return false;
}

然而,这种算法似乎无法找到根节点。如果您可以通过cid识别当前节点,而不是查看它的所有子节点,那会更好:

if (this /*… is what we have searched for */)
    return this;
findViewByCid: function(cid, children) {
    var col = (arguments.length === 1) ? this.children : children;
    if(cid in col){
        return col[cid];
    }       
    for(var childKey in col) {
        var grandChildren = col[childKey].children,
            childView;
        if (grandChildren) {
            childView = this.findViewByCid(cid, grandChildren);
        }
        if (childView) {
            return childView;
        }
    }
    return null;
}

首先,这看起来像Backbone.js,如果是的话,标记它可能会很有帮助。我觉得人们可能遇到过类似的问题,并且知道更好的方法来存储对视图的引用。

你只想在找到东西的时候归还。。。只要在第一个递归调用中使用return,就会在搜索第一组孙时强制该方法停止执行,即使什么都没有找到。

我还想在for循环中引入的新变量前面添加一个var——如果没有它,这个变量将是全局的。

这就是我最终得到的结果,它是backbone.rionette,用collectionView的itemView迭代collectionView:

findViewByCid: function(cid){
  var self = this,
      ret;
  function findView(cid, children){
    var col = (arguments.length === 1) ? self.children : children,
    grandChildren;
    if(cid in col){
      ret = col[cid];
    }
    for(child in col){
      grandChildren = col[child].children;
      if(cid in grandChildren){
        ret = grandChildren[cid];
      }
      if(grandChildren && (!jQuery.isEmptyObject(grandChildren))){
        findView(cid, grandChildren);
      }
    }
  };
  findView(cid);
  return ret;
}

我相信if(col中的cid)行不是你想做的。试试

findViewByCid: function(cid, children){
  if (this.cid === cid) return this;
  var col = (arguments.length === 1) ? this.children : children;
  for(var childI in col){
    var child = col[childI];
    if (child.cid === cid) {
      return child;
    }
    var grandChildren = child.children;
    if(grandChildren && (!jQuery.isEmptyObject(grandChildren))){
      return this.findViewByCid(cid, grandChildren);
    }
  }
}