2011-05-14 99 views
0

我想用一些新值(文本/對象/數組)來分配json對象內的元素。我有一個swap函數,它接受json對象,一個帶索引的數組來檢索元素和值來替換它。目前我正在使用eval,它符合一些是「邪惡」的。有沒有更好的方法來做到這一點,沒有評估或在這種情況下評估是好的?請記住它必須是動態的,因爲數組可能會改變。此外,注意到我正在編程創建數組參數可能很重要。在多維數組中爲節點賦值javascript

//array looks like: ["cluster", "2", "segment", "0", "node", "3"]  
JsonManager.prototype.swap = function(json, array, val){ 
     var statement = "json"; 
     for (var i = 0; i < array.length; i++) { 
      if(!isNumeric(array[i])) 
      { 
      statement += "[\"" + array[i] + "\"]";   
      }else{ 
       statement += "[" + array[i] + "]" 
      } 
     } 
     statement += " = val"; 
     eval(statement); 
    }; 

示例JSON對象:

var customers = { 
    "cluster": [{ 
     "clusterid": "cluster1.1", 
     "color": "blue", 
     "flights": "784", 
     "profit": "524125", 
     "clv": "2364", 
     "segment": [{ 
      "segmentid": "segment1.1", 
      "color": "green", 
      "flights": "82", 
      "profit": "22150", 
      "clv": "1564", 
      "node": [{ 
       "nodeid": "node1.1", 
       "color": "orange", 
       "xpos": "1", 
       "ypos": "1" 
      }, { 
       "nodeid": "node1.2", 
       "color": "blue", 
       "xpos": "1", 
       "ypos": "2" 
      }, { 
       "nodeid": "node1.3", 
       "color": "orange", 
       "xpos": "1", 
       "ypos": "3" 
      }, { 
       "nodeid": "node1.4", 
       "color": "orange", 
       "xpos": "1", 
       "ypos": "4" 
      }] 
     }, { 
      "segmentid": "segment1.2", 
      "color": "red", 
      "flights": "2", 
      "profit": "2150", 
      "clv": "1564", 
      "node": [{ 
       "nodeid": "node2.1", 
       "color": "tan", 
       "xpos": "2", 
       "ypos": "1" 
      }, { 
       "nodeid": "node2.2", 
       "color": "tan", 
       "xpos": "2", 
       "ypos": "2" 
      }, { 
       "nodeid": "node2.3", 
       "color": "tan", 
       "xpos": "2", 
       "ypos": "3" 
      }, { 
       "nodeid": "node2.4", 
       "color": "tan", 
       "xpos": "2", 
       "ypos": "4" 
      }] 
     }] 
    }, { 
     "clusterid": "cluster1.2", 
     "flights": "4", 
     "profit": "5245", 
     "clv": "2364", 
     "segment": [{ 
      "segmentid": "segment1.2", 
      "flights": "2", 
      "profit": "2150", 
      "clv": "1564", 
      "node": [{ 
       "nodeid": "node3.1", 
       "xpos": "3", 
       "ypos": "1" 
      }, { 
       "nodeid": "node3.2", 
       "xpos": "3", 
       "ypos": "2" 
      }, { 
       "nodeid": "node3.3", 
       "xpos": "3", 
       "ypos": "3" 
      }, { 
       "nodeid": "node3.4", 
       "xpos": "3", 
       "ypos": "4" 
      }] 
     }] 
    }, { 
     "clusterid": "cluster1.3", 
     "flights": "10", 
     "profit": "456978", 
     "clv": "548", 
     "segment": [{ 
      "segmentid": "segment1.3", 
      "flights": "2", 
      "profit": "2150", 
      "clv": "1564", 
      "node": [{ 
       "nodeid": "node4.1", 
       "xpos": "4", 
       "ypos": "1" 
      }, { 
       "nodeid": "node4.2", 
       "xpos": "4", 
       "ypos": "2" 
      }, { 
       "nodeid": "node4.3", 
       "xpos": "4", 
       "ypos": "3" 
      }, { 
       "nodeid": "node4.4", 
       "xpos": "4", 
       "ypos": "7" 
      }] 
     }] 
    }] 
}; 

這裏是我的測試方法:在這裏

JsonManager.prototype.init = function(){ 
    var clause = new Clause("nodeid", "node4.4"); 
    var indexes = this.search(customers, clause); 
    this.swap(customers, indexes.reverse(), {"name": "kevin"}); 
    var test = customers["cluster"][2]["segment"][0]["node"][3]; //hard coded pointer to node4.4 
    var breakPoint = "breakpoint"; //Just used as a point to stop the debugger to see test 
}; 

以供將來參考是進一步評論的解決方案:

JsonManager.prototype.swap = function(obj, path, value) { 

    //This is the inner function we are recursing into 
    function descend(obj, path) { 
    /*This if statement is used to stop the recrusion, 
    when we have iterated through all the paths, it returns 
    the object above our desired object */ 
     if (path.length == 0) { 
      return obj; 
     } 
    /*Recurse into the function passing in the top level object and remove 
    the top level object from our path*/ 
     return descend(obj[path[0]], path.slice(1)); 
    } 
//Pass in the object and the (path - the last element) 
    var node = descend(obj, path.slice(0, -1)); 
//Get the last node in path, pull it from node and assign the value 
    node[path[path.length - 1]] = value; 
}; 

回答

1

你「 JSON「對象只是一個JavaScript對象。更重要的是,它是一棵樹,使用遞歸樹最容易遍歷。

JsonManager.prototype.swap = function(obj, path, value) { 
    function descend(obj, path) { 
     if (path.length == 0) { 
      return obj; 
     } 
     return descend(obj[path[0]], path.slice(1)); 
    } 

    var node = descend(obj, path.slice(0, -1)); 
    node[path[path.length - 1]] = value; 
}; 

slice將從數組中取出塊。所以path.slice(1)返回path沒有第一個元素,和path.slice(0, -1)返回它沒有最後一個。這意味着我們descend到倒數第二個節點的對象,然後使用普通數組表示法設置最後一個節點。讓你頭腦清醒的最簡單方法是用紙張上的手動工作,例如上面的例子。

+0

處理整個樹是具有遞歸更容易,但訪問單個元素實際上更容易一個簡單的循環。 – Guffa 2011-05-14 12:16:45

+0

@Samir Talwar,感謝您的回答,該方法有效,我將坐下來了解正在發生的事情。它看起來像你在遞歸中使用閉包。那是對的嗎? – 2011-05-14 12:37:04

+0

@Samir Talwar你的對象如何保留對象的引用,而Guffa的不是?我通過你的代碼工作並評論它,所以我理解它,它包含在我的問題中。 – 2011-05-14 12:58:09

1

沒有理由使用eval爲,只是對象分配給一個變量,並使用該變量踏入每個級別:

JsonManager.prototype.swap = function(json, array, val){ 
    var j = json; 
    for (var i = 0; i < array.length - 1; i++) { 
    j = j[array[i]]; 
    } 
    j[array[array.length - 1]] = val; 
}; 
+0

我發佈問題之前嘗試使用此方法。我相信它存在一個問題,因爲儘管json對象是通過引用傳入的,但是當您將它的一段分配給j時,它是通過值完成的。當我用你的功能替換我的功能時,值不會改變。我錯過了什麼嗎?我已將我的測試方法添加到最初的帖子中。 – 2011-05-14 12:27:10

+0

@ kmb385:是的,你說得對,但這只是問題的最後一步,因爲這是唯一一個值,而不是對象。我直接將代碼更改爲最後一步,而不是將其分配給變量。 – Guffa 2011-05-14 23:36:08

+0

感謝您的解決方案,我將在這兩個函數上放置一個秒錶,並查看哪個效率最高。 – 2011-05-15 13:28:44