Eu tenho um grande objeto que desejo converter para JSON e enviar. No entanto, possui estrutura circular. Quero lançar todas as referências circulares existentes e enviar o que puder ser especificado. Como faço isso?
Obrigado.
var obj = {
a: "foo",
b: obj
}
Quero restringir obj em:
{"a":"foo"}
javascript
json
node.js
atormentar
fonte
fonte
Respostas:
Use
JSON.stringify
com um substituto personalizado. Por exemplo:O substituto neste exemplo não está 100% correto (dependendo da sua definição de "duplicado"). No seguinte caso, um valor é descartado:
Mas o conceito permanece: use um substituto personalizado e acompanhe os valores do objeto analisado.
Como uma função utilitária escrita em es6:
fonte
Node.prototype.toJSON = function() { return 'whatever you think that is right'; };
(se desejar algo mais genérico / específico, tente algo na árvore de protótipos: HTMLDivElement implementa implementos HTMLElement implementos elemento Node implementos EventTarget; nota: isto pode ser dependente do navegador, a árvore anterior é verdadeiro para Chrome)var a={id:1}; JSON.stringify([a,a]);
cache
será inacessível developer.mozilla.org/en-US/docs/Web/JavaScript/…No Node.js, você pode usar o utilitário.inspect (objeto) . Ele substitui automaticamente os links circulares por "[Circular]".
Apesar de estar embutido (nenhuma instalação é necessária) , você deve importá-lo
Para usá-lo, basta chamarLembre-se também de que você pode passar o objeto de opções para inspecionar (veja o link acima)
Por favor, leia e dê elogios aos comentaristas abaixo ...
fonte
var util = require('util');
obj_str = util.inspect(thing)
, NÃO <s>garbage_str = JSON.stringify(util.inspect(thing))
</s> #Gostaria de saber por que ninguém postou a solução adequada da página MDN ainda ...
Os valores vistos devem ser armazenados em um conjunto , não na matriz (o substituto é chamado em todos os elementos ) e não há necessidade de tentar
JSON.stringify
cada elemento da cadeia que leva a uma referência circular.Como na resposta aceita, esta solução remove todos os valores repetidos , não apenas os circulares. Mas pelo menos não tem complexidade exponencial.
fonte
replacer = () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); } return value; }; } () => { const seen = new WeakSet(); return (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return; } seen.add(value); … JSON.stringify({a:1, b: '2'}, replacer)
retornaundefined
no chromeapenas faça
então no seu arquivo js
https://github.com/WebReflection/circular-json
NOTA: Não tenho nada a ver com este pacote. Mas eu uso para isso.
Atualização 2020
Observe que o CircularJSON está apenas em manutenção e o seu sucessor é achatado .
fonte
JSON
por princípio.Flatted.stringify({blah: 1})
resulta em[{"blah":1}]
) vejo alguém tentando levantar uma questão sobre isso, e o autor repreendeu-a e bloqueou a questão para comentários.Eu realmente gostei da solução do Trindaz - mais detalhada, porém tinha alguns bugs. Eu os consertei para quem gosta também.
Além disso, adicionei um limite de comprimento nos meus objetos de cache.
Se o objeto que estou imprimindo for realmente grande - quero dizer infinitamente grande -, quero limitar meu algoritmo.
fonte
@ A resposta de RobW está correta, mas isso é mais eficiente! Porque ele usa um hashmap / set:
fonte
{"a":{"b":{"a":"d"}}}
e até removendo nós com objeto vazio {}Observe que também há um
JSON.decycle
método implementado por Douglas Crockford. Veja o seu cycle.js . Isso permite que você especifique quase qualquer estrutura padrão:Você também pode recriar o objeto original com o
retrocycle
método Portanto, você não precisa remover os ciclos dos objetos para especificá-los.No entanto, isso não funcionará para nós DOM (que são a causa típica de ciclos em casos de uso da vida real). Por exemplo, isso jogará:
Fiz um garfo para resolver esse problema (veja meu garfo cycle.js ). Isso deve funcionar bem:
Observe que no meu fork
JSON.decycle(variable)
funciona como no original e lançará uma exceção quando osvariable
nós / elementos do DOM contiverem.Ao usar,
JSON.decycle(variable, true)
você aceita o fato de que o resultado não será reversível (o retrociclo não recriará os nós do DOM). Os elementos DOM devem ser identificados até certo ponto. Por exemplo, se umdiv
elemento tiver um ID, ele será substituído por uma sequência"div#id-of-the-element"
.fonte
JSON.decycle(a, true)
o que acontece quando você passa true como um parâmetro para reciclar a função.stringifyNodes
opção verdadeira no garfo. Isso irá despejar por exemplo,div
com id = "some-id" a string:div#some-id
. Você evitará alguns problemas, mas não poderá retroceder completamente.Eu recomendo verificar o json-stringify-safe do @ isaacs-- é usado no NPM.
Para instalar:
Usar:
Isso produz:
fonte
Para futuros googlers que procuram uma solução para esse problema quando não conhecem as chaves de todas as referências circulares, você pode usar um wrapper em torno da função JSON.stringify para descartar referências circulares. Veja um script de exemplo em https://gist.github.com/4653128 .
A solução basicamente se resume em manter uma referência a objetos impressos anteriormente em uma matriz e verificar isso em uma função substituta antes de retornar um valor. É mais constritivo do que excluir as referências circulares, porque também descarta a impressão de um objeto duas vezes, um dos efeitos colaterais é o de evitar referências circulares.
Exemplo de wrapper:
fonte
if(printedObjIndex)
enquanto deve escrever,if(printedObjIndex==false)
porqueindex
também pode ser0
traduzido parafalse
, a menos que você indique explicitamente o contrário.===
?0 == false
étrue
,0 === false
éfalse
. ; ^) Mas eu prefiro não inicializarprintedObjIndex
como false, pois então você podeundefined
comparar para que você (bem, o de Trindaz) não misture metáforas tão estranhamente.Use o método JSON.stringify com um substituto. Leia esta documentação para obter mais informações. http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx
Descubra uma maneira de preencher a matriz de substituição com referências cíclicas. Você pode usar o método typeof para descobrir se uma propriedade é do tipo 'objeto' (referência) e uma verificação exata de igualdade (===) para verificar a referência circular.
fonte
var obj = {foo:obj}
não não criar uma referência circular. Em vez disso, ele cria um objeto cujofoo
atributo se refere ao valor anterior deobj
(undefined
se não definido anteriormente, declarado por causavar obj
).E se
resulta em um
Então você pode imprimir assim:
fonte
avalia como:
com a função:
fonte
Sei que essa é uma pergunta antiga, mas gostaria de sugerir um pacote NPM que criei chamado smart-circular , que funciona de maneira diferente das outras maneiras propostas. É especialmente útil se você estiver usando objetos grandes e profundos .
Alguns recursos são:
Substituindo referências circulares ou simplesmente estruturas repetidas dentro do objeto pelo caminho que leva à sua primeira ocorrência (não apenas a string [circular] );
Ao procurar circularidades em uma pesquisa abrangente, o pacote garante que esse caminho seja o menor possível, o que é importante ao lidar com objetos muito grandes e profundos, nos quais os caminhos podem ser irritantemente longos e difíceis de seguir (a substituição personalizada em JSON.stringify faz um DFS);
Permite substituições personalizadas, úteis para simplificar ou ignorar partes menos importantes do objeto;
Por fim, os caminhos são escritos exatamente da maneira necessária para acessar o campo referenciado, o que pode ajudá-lo a depurar.
fonte
O segundo argumento para JSON.stringify () também permite especificar uma matriz de nomes de chaves que devem ser preservados de todos os objetos encontrados nos seus dados. Isso pode não funcionar para todos os casos de uso, mas é uma solução muito mais simples.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Nota: Estranhamente, a definição de objeto do OP não gera um erro de referência circular no Chrome ou Firefox mais recente. A definição nesta resposta foi modificada para que ele fez lançar um erro.
fonte
Para atualizar a resposta de substituir a maneira como o JSON funciona (provavelmente não recomendado, mas super simples), não use
circular-json
(está obsoleto). Em vez disso, use o sucessor, achatado:https://www.npmjs.com/package/flatted
Emprestado da resposta antiga acima de @ user1541685, mas substituído pela nova:
npm i --save flatted
então no seu arquivo js
fonte
Encontrei a biblioteca circular-json no github e funcionou bem para o meu problema.
Algumas boas características que achei úteis:
fonte
Eu resolvo esse problema assim:
fonte
_class: ClassName { data: "here" }
, então eu adicionei a regra a seguir.replace(/(\w+) {/g, '{ __ClassName__: "$1", ')
. No meu caso, eu estava tentando ver como era um objeto de solicitação http.Eu sei que esta pergunta é antiga e tem muitas ótimas respostas, mas eu posto essa resposta por causa de seu novo sabor (es5 +)
Mostrar snippet de código
fonte
Embora isso tenha sido respondido suficientemente, você também pode excluir explicitamente a propriedade em questão antes da stringização usando o
delete
operador.operador de exclusão
isso removerá a necessidade de criar ou manter uma lógica complexa para remover referências circulares.
fonte
fonte
uma outra solução para resolver esse problema com esse tipo de objeto é que o uso dessa biblioteca
https://github.com/ericmuyser/stringy
é simples e você pode, em alguns passos simples, resolver isso.
fonte
Com base nas outras respostas, acabo com o código a seguir. Funciona muito bem com referências circulares, objetos com construtores personalizados.
Do objeto especificado a ser serializado,
Link do Github - DecycledJSON
Exemplo de uso 1:
Exemplo de uso 2:
fonte
Tente o seguinte:
fonte
seen.push(value)
= -D? Comofor (var key in value) {value[key] = circular_replacer(value[key]);}
Na minha solução, se você se deparar com um ciclo, ele não diz apenas "ciclo" (ou nada), mas algo como foo: veja o objeto nº 42 acima e para ver onde foo aponta, você pode rolar para cima e pesquisar para o objeto # 42 (cada objeto, quando iniciado, diz o objeto # xxx com algum número inteiro xxx)
Snippet:
fonte