2013-07-19 53 views
4

我正在處理一個項目,該項目有一個瘋狂的for循環來展開D3.js畫布交互式中的節點。基本上,我想要的是擴大所有的孩子。所以如果一個物體有一個孩子,我想擴大它們。For循環在對象上失控

我從這裏刪去了一大塊代碼。有太多的循環是荒謬的。我怎樣才能減少到一個簡單的「找到所有的孩子,preform切換();和更新();」?

$('.expandAll').click(function(e) { 
    e.preventDefault(); 
    length = root.children.length; 

    for (var i = 0; i < length; i++) { 
     toggle(root.children[i]); 
     update(root); 

     if (root.children[i]['children']) { 
      childlength = root.children[i]['children'].length; 

      for (var j = 0; j < childlength; j++) { 
       toggle(root.children[i]['children'][j]); 
       update(root); 

       if (root.children[i]['children'][j]['children']) { 
        childlength2 = root.children[i]['children'][j]['children'].length; 

        for (var k = 0; k < childlength2; k++) { 
         toggle(root.children[i]['children'][j]['children'][k]); 
         update(root); 
        } 
       } 
      } 
     } 
    } 
}); 
+2

這......這是失控了!停止主反應堆! ......但真的。爲什麼不只是建立一些功能? – jdero

+3

遞歸!遞歸!遞歸! –

+0

你知道嗎,遞歸函數是什麼? 是否遞歸 –

回答

3

聽起來像是一個很好的例子遞歸:

$('.expandAll').click(function(e) { 
    e.preventDefault(); 

    expandAll(root); 
}); 

var expandAll = function (node) { 
    toggle(node); 
    update(node); 

    // edit: if nodes with no children are lacking the children property 
    if (!node.children) { 
     return; 
    } 

    for (var i = 0, length = node.children.length; i < length; i++) { 
     expandAll(node.children[i]); 
    } 
}; 

我不知道什麼toggleupdate究竟意味着什麼,但你可以後執行只是一個單一的頂級update通話呼叫expandAll(root);

+0

這將導致堆棧溢出或'無法訪問'我'未定義的異常?看起來葉節點確實有* no * children數組而不是一個長度爲0. – Bergi

+0

@Bergi聽起來像是節點對象的問題,而不是循環:) – jbabey

+0

是的,我剛剛得到「無法讀取長度的屬性」 。 – dallen

0

使用recursion!如果您只需要支持三個級別,則可以爲此引入一個計數器變量。

$('.expandAll').click(function(e) { 
    e.preventDefault(); 
    expandAll(root, root.children/*, 3*/); 
} 
function expandAll(root, children/*, lev*/) { 
    if (!children/* || lev<=0 */) return; 
    var length = children.length; 
    for (var i = 0; i < length; i++) { 
     toggle(children[i]); 
     update(root); 
     expandAll(root, children[i].children/*, lev-1*/); 
    } 
} 

順便說一句,你確定,你需要每一個toggle後呼籲rootupdate?當所有的孩子都被切換時,最後一次稱呼它會更有意義。

0

不知道這是否會幫助,但東西我已經和嵌套對象做:

object = { 
    children: [], // array of similar objects with children property and update function 
    update: function(data){ 
     // update this item 
     this.data = data; 

     // update each immediate child 
     if (this.children) 
      for (var i in this.children) 
       this.children[i].update(data); 
    } 
}; 

// then you just call update on the first item: 
object.update(data); 

如果按照這種模式,而不是在根級別設置複雜的循環,你只需遍歷直接的孩子,並呼籲他們的更新功能,然後循環通過他們的孩子,並一路下降。

我不是一個偉大的JS開發者,只是我在做什麼,因爲我是用一天工作的一些嵌套的註釋;)