【问题标题】:Recursive JavaScript returning after first pass第一次通过后返回的递归 JavaScript
【发布时间】:2012-08-21 13:22:44
【问题描述】:

我有以下递归 javascript 函数,它循环遍历具有子 ItemViews 又是 CollectionViews 的主干.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

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

如果我删除 return 语句,找到正确的孩子但返回 null。

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

【问题讨论】:

    标签: javascript recursion marionette


    【解决方案1】:

    return 将退出您的函数

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

    这是一个建议

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

    【讨论】:

      【解决方案2】:

      只有在找到某些东西时才需要返回,否则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;
      

      【讨论】:

        【解决方案3】:
        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.marionette,我正在使用一个CollectionView 的ItemView 迭代CollectionView,使其比平时复杂一些。
        【解决方案4】:

        这就是我最终得到的结果,它是主干.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;
        }
        

        【讨论】:

          【解决方案5】:

          我相信 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);
              }
            }
          }
          

          【讨论】:

          • 很难解释。考虑 cid 为 5。模型中的 cid 检查是否存在 model[5] 与 model['cid'] === 5 或 model.cid === 5 不同。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-27
          • 2014-09-10
          • 2016-05-26
          • 1970-01-01
          • 1970-01-01
          • 2012-05-02
          • 2012-05-29
          相关资源
          最近更新 更多