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

时间:2012-08-21 13:22:45

标签: javascript recursion marionette

我有以下递归javascript函数,它循环遍历backbone.marionette CollectionView的子节点,它们具有子集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。

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

5 个答案:

答案 0 :(得分:0)

返回会退出您的功能

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

以下是建议

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

答案 1 :(得分:0)

只有在找到某些内容时才需要返回,否则return语句将在不搜索其他子项的情况下中断循环。这是一个简单的depth-first-search你想要的东西。

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

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;

答案 2 :(得分:0)

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 - 没有它,变量将是全局变量。

答案 3 :(得分:0)

这是我最终得到的,它是backbone.marionette,使用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;
}

答案 4 :(得分:-1)

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

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