我正在製作一款遊戲,並且遇到了一個問題......當我嘗試保存時,JSON失敗並報告正在製作循環引用。我不認爲它是真的,我看不到它,所以有算法或任何可以告訴我它究竟在哪裏(在哪些對象和東西之間)的算法?另外,有沒有可以保存循環引用的JSON替代方案?我正在運行一個node.js服務器,我看到了this,但是我無法讓它工作(它不是作爲一個模塊,我可以在我的代碼中需要())。有沒有辦法在JavaScript中測試循環引用?
回答
如果您想要序列化一個循環引用以便保存它,則需要將引用設置爲「虛擬」,因爲它不能被序列化爲循環引用,因爲這會導致序列化來序列化同一個圓永遠的對象(或者至少在運行時耗盡內存之前)。
因此,不是存儲循環引用本身,而是存儲一個指向該對象的指針。這個指針就像ref : '#path.to.object'
這樣的東西,當你反序列化時可以解決這個問題,所以你將引用指向實際的對象。你只需要打破序列化的參考,以便能夠序列化它。
發現在JavaScript中循環引用可以通過在陣列中的所有對象(用for (x in y)
),商店x
與恆等算子(也稱爲strict comparison operator)===
臨時數組中遞歸地迭代和比較每個x
每個z
來完成。每當x === z
等於true時,用佔位符替換引用x
,該佔位符將被序列化到上述ref
。
,以保持一個數組在「參觀」的對象另一種方法是「污點」的你在這個非常簡單的例子對它們設置屬性,就像遍歷對象:
for (x in y) {
if (x.visited) {
continue;
}
x.visited = true;
}
沒有好檢測對象中的圓形的方法,但是通過遍歷對象樹並檢查引用也是可能的。我烤了,試圖檢測一個節點已經被用作其父
function isCircularObject(node, parents){
parents = parents || [];
if(!node || typeof node != "object"){
return false;
}
var keys = Object.keys(node), i, value;
parents.push(node); // add self to current path
for(i = keys.length-1; i>=0; i--){
value = node[keys[i]];
if(value && typeof value == "object"){
if(parents.indexOf(value)>=0){
// circularity detected!
return true;
}
// check child nodes
if(arguments.callee(value, parents)){
return true;
}
}
}
parents.pop(node);
return false;
}
和使用將是isCircularObject(obj_value)
其中函數,如果圓存在,false
如果沒有返回true
一個節點行走功能。
// setup test object
var testObj = {
property_a:1,
property_b: {
porperty_c: 2
},
property_d: {
property_e: {
property_f: 3
}
}
}
console.log(isCircularObject(testObj)); // false
// add reference to another node in the same object
testObj.property_d.property_e.property_g = testObj.property_b;
console.log(isCircularObject(testObj)); // false
// add circular node
testObj.property_b.property_c = testObj.property_b;
console.log(isCircularObject(testObj)); // true
的關鍵點是一個對象的值是具有其他值僅等於如果它是同一個對象引用,而不是當它的另一對象(即使完全相似)。
非常感謝! – corazza
我正在考慮你想要完成什麼,基於你的另一個問題的初始代碼。爲什麼不做這樣的事情。
Player = function()
{
this.UnitTypeXpower = 2
this.UnitTypeYpower = 7
}
UnitTypeXAdd = function(owner)
{
owner.UnitTypeXpower++;
}
這樣,你不必使用循環引用,它可以完成同樣的事情。
我使用的實際對象要複雜得多,我把它放在一個佔位符中,因爲把整個代碼放在那裏是一個壞主意...... – corazza
這是Andris的答案的一個小擴展,告訴你第一個圓形元素在哪裏,以便相應地處理它。
function findCircularObject(node, parents, tree){
parents = parents || [];
tree = tree || [];
if (!node || typeof node != "object")
return false;
var keys = Object.keys(node), i, value;
parents.push(node); // add self to current path
for (i = keys.length - 1; i >= 0; i--){
value = node[keys[i]];
if (value && typeof value == "object") {
tree.push(keys[i]);
if (parents.indexOf(value) >= 0)
return true;
// check child nodes
if (arguments.callee(value, parents, tree))
return tree.join('.');
tree.pop();
}
}
parents.pop();
return false;
}
如果你不想要一個字符串,樹數組是不必要的。只要改變原有的功能,以
return value;
的圓形物體本身或
return parents.pop();
其父。
這裏是我用來檢測循環引用的代碼,它使用accepted answer by asbjornu中建議的技術,每個值都會遍歷並將其引用保存在一個數組中,以便可以比較下一個值與之前走過的人一樣。
function isCircular(obj, arr) {
"use strict";
var type = typeof obj,
propName,
//keys,
thisVal,
//iterKeys,
iterArr,
lastArr;
if (type !== "object" && type !== "function") {
return false;
}
if (Object.prototype.toString.call(arr) !== '[object Array]') {
//if (!Array.isArray(arr)) {
type = typeof arr; // jslint sake
if (!(type === "undefined" || arr === null)) {
throw new TypeError("Expected attribute to be an array");
}
arr = [];
}
arr.push(obj);
lastArr = arr.length - 1;
for (propName in obj) {
//keys = Object.keys(obj);
//propName = keys[iterKeys];
//for (iterKeys = keys.length - 1; iterKeys >= 0; iterKeys -= 1) {
thisVal = obj[propName];
//thisVal = obj[keys[iterKeys]];
type = typeof thisVal;
if (type === "object" || type === "function") {
for (iterArr = lastArr; iterArr >= 0; iterArr -= 1) {
if (thisVal === arr[iterArr]) {
return true;
}
}
// alternative to the above for loop
/*
if (arr.indexOf(obj[propName]) >= 0) {
return true;
}
*/
if (isCircular(thisVal, arr)) {
return true;
}
}
}
arr.pop();
return false;
}
此代碼在jsfiddle上可用,您可以在此自行測試。 我也在jsperf上運行過一些性能測試。
Array.indexOf
才被推出,如JavaScript 1.6,見MDN page
Array.isArray
才被推出,如JavaScript 1.8.5,請參閱MDN page
Object.keys
才被推出,如JavaScript 1.8.5,請參閱MDN page
還值得注意的是arguments.callee
在嚴格模式下被棄用和禁止,優先使用命名的樂趣ctions
您的代碼可以這樣簡化:try { JSON.stringify( OBJ); 返回true; (e){ return false; } catch(e){ return false; } –
OP寫道:「我正在製作一款遊戲,並且遇到了一個問題......當我嘗試保存時,JSON失敗並報告說正在製作循環引用。我不認爲它是真的,我看不到它,所以有算法或任何可以告訴我它究竟在哪裏(在哪些對象和東西之間)的算法?另外,有沒有可以保存循環引用的JSON替代方案?我正在運行一個node.js服務器,我看到了這個,但是我無法實現它的功能(它不是作爲一個模塊,我可以在我的代碼中需要())。 ' – Xotic750
- 1. 使用StructureMap時,有沒有辦法檢測和調試循環引用?
- 2. 有沒有辦法在純PHP中檢測循環數組?
- 3. 有沒有辦法在循環中重新使用Formatter對象?
- 4. 有沒有辦法在ant中循環使用ant-contrib文件?
- 5. 有沒有辦法在cql文件cassandra中應用循環?
- 6. 在ASP.NET MVC中,使用EditorTemplates時有沒有辦法獲得循環索引?
- 7. 有沒有辦法測試CSS文件?
- 8. 有沒有辦法測試變量「isForEachable」
- 9. 有沒有辦法在TeamCity中訂購JUnit測試用例?
- 10. 有沒有辦法在Elixir中使用Doctest測試IO輸出?
- 11. 有沒有辦法在Java中無限循環地圖元素?
- 12. 有沒有辦法在HAML的javascript區域內使用Ruby循環?
- 13. 有沒有辦法在Xcode4中「測試」當前文件?
- 14. 有沒有辦法取消在Selenium Grid中運行測試?
- 15. 有沒有辦法在單元測試中覆蓋處理器?
- 16. 有沒有辦法在基類中跳過測試?
- 17. 有沒有辦法在Monotouch 4/Monodevelop中做單元測試?
- 18. 有沒有人曾經使用AOP來檢測循環引用?
- 19. 有沒有辦法在Javascript中檢測DOM節點的變化?
- 20. 有沒有辦法在JavaScript中檢測下載的開始?
- 21. 有沒有辦法在javascript中檢測查看器的主頁?
- 22. 有沒有辦法在python的for循環中動態使用方法?
- 23. 有沒有辦法在Flutter單元測試中測試AppLifecycleState更改?
- 24. 有沒有辦法使用numpy去除循環?
- 25. 有沒有什麼辦法可以用Tag Helper創建循環?
- 26. 有沒有辦法使用numpy切片做循環置換?
- 27. 有沒有辦法從ActionScript中檢查循環參數的值?
- 28. 階乘在JavaScript中沒有循環
- 29. JavaScript - 有沒有辦法找出給定的字符是否包含在沒有循環的字符串中?
- 30. 有沒有辦法在循環中使用斷言來查找頁面
+1污染:) – dinjas