Sto facendo un gioco e mi sono imbattuto in un problema ... Quando provo a salvare, JSON fallisce e segnala che il riferimento circolare viene creato da qualche parte. Non penso che sia in realtà, non riesco a vederlo, quindi c'è un algoritmo o qualcosa che potrebbe dirmi dove è esattamente (tra quali oggetti e cose)? Inoltre, esiste un'alternativa JSON in grado di salvare riferimenti circolari? Sto utilizzando un server node.js, ho visto this, ma non riesco a farlo funzionare (non è stato creato come modulo che posso richiedere() nel mio codice).C'è un modo per testare il riferimento circolare in JavaScript?
risposta
Se si desidera serializzare un riferimento circolare per poterlo salvare, è necessario creare il riferimento "virtuale" in quanto non può essere serializzato come riferimento circolare, poiché ciò comporterebbe la serializzazione per serializzare la stessa cerchia di oggetti per sempre (o almeno fino a quando il runtime non ha esaurito la memoria).
Quindi, invece di memorizzare il riferimento circolare stesso, è sufficiente memorizzare un puntatore all'oggetto. Il puntatore sarà qualcosa come ref : '#path.to.object'
che può essere risolto quando si deserializza in modo da puntare il riferimento all'oggetto reale. Hai solo bisogno di rompere il riferimento sulla serializzazione per poterlo serializzare.
scoprendo un riferimento circolare in JavaScript può essere fatto ricorsivamente scorrendo tutti gli oggetti (con for (x in y)
), magazzini x
in un array e confrontare ogni x
con l'operatore identità (pseudonimo strict comparison operator) ===
per ogni z
nella matrice temporanea. Ogni volta che x === z
è uguale a vero, sostituire il riferimento a x
con un segnaposto che verrà serializzato al numero sopra menzionato ref
.
Un'alternativa a mantenere una matrice sugli oggetti "visitati" è quello di "Taint" gli oggetti che si scorrere impostando una proprietà su di loro, come in questo esempio molto ingenua:
for (x in y) {
if (x.visited) {
continue;
}
x.visited = true;
}
non c'è alcun bene modo per rilevare la circolarità negli oggetti ma è possibile camminando nell'albero degli oggetti e controllando i riferimenti. Ho sfornato una funzione di nodo-walking che cerca di rilevare se un nodo è stato già utilizzato come suo genitore
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;
}
E l'uso sarebbe isCircularObject(obj_value)
in cui la funzione restituisce true
se circolarità esiste e se non false
.
// 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
Il punto chiave è che un valore oggetto è uguale con un altro valore unicose è lo stesso riferimento oggetto e non quando è un altro oggetto (anche se tutto simile).
Grazie mille! – corazza
Stavo pensando a quello che stai cercando di realizzare in base al codice iniziale della tua altra domanda. Perché non fare qualcosa di simile.
Player = function()
{
this.UnitTypeXpower = 2
this.UnitTypeYpower = 7
}
UnitTypeXAdd = function(owner)
{
owner.UnitTypeXpower++;
}
In questo modo non è necessario utilizzare un riferimento circolare e realizza la stessa cosa.
Gli oggetti reali che uso sono molto più complessi, ho messo il potere proprio come un segnaposto, perché mettere l'intero codice sarebbe una cattiva idea ... – corazza
Questa è una piccola estensione della risposta di Andris che ti dice dove è il primo elemento circolare in modo che tu possa occuparti di conseguenza.
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;
}
Se non si desidera una stringa, l'array tree non è necessario.Basta cambiare la funzione originale di
return value;
per l'oggetto circolare stesso o
return parents.pop();
per il suo genitore.
Ecco il codice che sto usando per rilevare riferimenti circolari, utilizza la tecnica che è stata suggerita nel accepted answer by asbjornu, in cui ogni valore è calpestato e il suo riferimento è mantenuto in una matrice in modo che il valore successivo possa essere confrontato con quelli precedentemente camminati.
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;
}
Questo codice è disponibile sul jsfiddle, dove è possibile testare in prima persona. Ho anche eseguito alcuni test delle prestazioni su jsperf.
Array.indexOf
è stato introdotto solo a partire dal Javascript 1.6, vedere MDN page
Array.isArray
è stato introdotto solo a partire dal JavaScript 1.8.5, vedere MDN page
Object.keys
è stato introdotto solo a partire dal JavaScript 1.8.5, vedere MDN page
Vale anche la pena notare che arguments.callee
è deprecato e vietato in modalità rigorosa in preferenza all'utilizzo di named fun cations
Il tuo codice può essere semplificato in questo modo: prova { JSON.stringify (obj); return true; } catch (e) { return false; } –
OP ha scritto: "Sto facendo un gioco, e ho trovato un problema ... Quando provo a salvare, JSON fallisce e segnala che il riferimento circolare viene fatto da qualche parte. Non penso che sia in realtà, non riesco a vederlo, quindi c'è un algoritmo o qualcosa che potrebbe dirmi dove è esattamente (tra quali oggetti e cose)? Inoltre, esiste un'alternativa JSON in grado di salvare riferimenti circolari? Sto eseguendo un server node.js, l'ho visto, ma non riesco a farlo funzionare (non è stato creato come modulo che posso richiedere() nel mio codice). ' – Xotic750
- 1. Esempio di riferimento circolare in Javascript?
- 2. incatenato assegnazione e riferimento circolare in JavaScript
- 3. Stringify (convert to JSON) un oggetto JavaScript con riferimento circolare
- 4. serializzatore Symfony - imposta il riferimento circolare globale
- 5. Qual è il modo migliore per testare javascript?
- 6. Riferimento circolare e costruttori
- 7. Entity Framework circolare Riferimento
- 8. Riferimento circolare con mangusta
- 9. Come risolvere il riferimento circolare della procedura?
- 10. Un modo per testare EventEmitter in Angular2?
- 11. Come accedere alla matrice in modo circolare in javascript
- 12. Riferimento circolare in C++ senza puntatori
- 13. Come rimuovere il riferimento circolare in Entity Framework?
- 14. Errore di riferimento circolare errato
- 15. Un riferimento "circolare" sarebbe considerato come "raggiungibilità" per una WeakMap?
- 16. Primavera esempio di riferimento circolare
- 17. Json e Java - Riferimento circolare
- 18. Riferimento circolare nel servizio web
- 19. Modo corretto per fare riferimento a Javascript in ASP.NET MVC?
- 20. Come creare un tipo di riferimento circolare in TypeScript?
- 21. Un modo corretto per testare le gemme
- 22. Tornando per riferimento in JavaScript?
- 23. Ho un riferimento circolare. Come posso creare un riferimento debole in Objective-C?
- 24. circolare riferimento fra due complessi NET
- 25. Il modo migliore per testare i valori booleani in Rspec
- 26. Evita il riferimento circolare nel modello di dominio
- 27. Riferimento Controllo ASP.NET per ID in JavaScript?
- 28. Creazione di un elenco collegato in modo circolare in C#?
- 29. Esiste un modo idiomatico per testare l'uguaglianza dell'array in Coffeescript?
- 30. Perché non riesco a far circolare un loop in Javascript?
+1 per contaminare :) – dinjas