1

我有以下递归 javascript 函数,它循环遍历具有子 ItemViews 又是 CollectionViews 的backbone.marionette CollectionView 的子代:

  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。

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

4

5 回答 5

0

这就是我最终得到的结果,它是主干.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;
}
于 2012-08-21T14:27:33.880 回答
0

return 将退出您的功能

尝试将所有内容保存在 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;
}
于 2012-08-21T13:30:51.527 回答
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 - 没有它,该变量将是全局的。

于 2012-08-21T14:15:33.813 回答
0

仅当找到某些内容时才需要返回,否则该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;
于 2012-08-21T13:44:46.213 回答
-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);
    }
  }
}
于 2012-08-21T13:33:13.707 回答