Aqui está um exemplo de uma estrutura de dados com referências cíclicas:
function makeToolshed(){
var nut = {name: 'nut'}, bolt = {name: 'bolt'};
nut.needs = bolt; bolt.needs = nut;
return { nut: nut, bolt: bolt };
}
Quando desejar MANTENHA as referências cíclicas (restaurá-los quando você desserializar, em vez de "nuking-los"), você tem 2 opções, o que eu vou comparar aqui. O primeiro é o cycle.js de Douglas Crockford , o segundo é o meu pacote da Sibéria . Ambos trabalham primeiro "deciclando" o objeto, ou seja, construindo outro objeto (sem nenhuma referência cíclica) "contendo a mesma informação".
O Sr. Crockford vai primeiro:
JSON.decycle(makeToolshed())
Como você vê, a estrutura aninhada do JSON é mantida, mas há uma coisa nova, que é objetos com a $ref
propriedade especial . Vamos ver como isso funciona.
root = makeToolshed();
[root.bolt === root.nut.needs, root.nut.needs.needs === root.nut]; // retutrns [true,true]
O cifrão representa a raiz. .bolt
ter $ref
nos diz que .bolt
é um objeto "já visto" e o valor dessa propriedade especial (aqui, a string $ ["nut"] ["needs"]) nos diz onde, veja primeiro ===
acima. Da mesma forma para o segundo $ref
e o segundo ===
acima.
Vamos usar um teste de igualdade profunda adequado (ou seja, a deepGraphEqual
função de Anders Kaseorg da resposta aceita a esta pergunta ) para ver se a clonagem funciona.
root = makeToolshed();
clone = JSON.retrocycle(JSON.decycle(root));
deepGraphEqual(root, clone) // true
serialized = JSON.stringify(JSON.decycle(root));
clone2 = JSON.retrocycle(JSON.parse(serialized));
deepGraphEqual(root, clone2); // true
Agora, na Sibéria:
JSON.Siberia.forestify(makeToolshed())
A Sibéria não tenta imitar JSON "clássico", nenhuma estrutura aninhada. O gráfico do objeto é descrito de maneira "plana". Cada nó do gráfico de objeto é transformado em uma árvore plana (lista de pares de valores de chave simples com valores somente inteiros), que é uma entrada em .forest.
No índice zero, encontramos o objeto raiz, em índices mais altos, encontramos os outros nós de o gráfico do objeto e os valores negativos (de alguma chave de alguma árvore da floresta) apontam para a atoms
matriz (que é digitada através da matriz de tipos, mas pularemos os detalhes da digitação aqui). Todos os nós terminais estão na tabela de átomos, todos os nós não terminais estão na tabela de floresta e é possível ver imediatamente quantos nós o gráfico de objetos possui, a saber forest.length
. Vamos testar se funciona:
root = makeToolshed();
clone = JSON.Siberia.unforestify(JSON.Siberia.forestify(root));
deepGraphEqual(root, clone); // true
serialized = JSON.Siberia.stringify(JSON.Siberia.forestify(root));
clone2 = JSON.Siberia.unforestify(JSON.Siberia.unstringify(serialized));
deepGraphEqual(root, clone2); // true
comparação
adicionará a seção mais tarde.