1

私は次の再帰的な JavaScript 関数を持っています。これは backbone.marionette CollectionView の子をループしています。これには、CollectionView である子 ItemView があります。

  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

次に、return ステートメントにより、th3 c2 ノードを通過した後に関数が終了し、c4 などに到達しません。

return ステートメントを削除すると、正しい子が見つかりますが、null が返されます。

階層の解析を続行して値を返すにはどうすればよいですか?

4

5 に答える 5

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 に答える
0

return は関数を終了します

すべてを 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;
}
于 2012-08-21T13:30:51.527 に答える
0

これは私が最終的に得たものであり、CollectionView の itemView を使用して collectionView を反復処理する backbone.marionette です。

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
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 に答える
-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 に答える