У меня есть большой объект, который я хочу преобразовать в JSON и отправить. Однако он имеет круглую структуру. Я хочу отбросить все существующие циклические ссылки и отправить все, что можно зачеркнуть. Как я могу это сделать?
Спасибо.
var obj = {
a: "foo",
b: obj
}
Я хочу преобразовать obj в:
{"a":"foo"}
javascript
json
node.js
Гарри
источник
источник
Ответы:
Используйте
JSON.stringify
с пользовательским заменителем. Например:Заменитель в этом примере не на 100% правильный (в зависимости от вашего определения «дубликат»). В следующем случае значение отбрасывается:
Но концепция стоит: использовать пользовательский заменитель и отслеживать проанализированные значения объекта.
Как функция полезности написана в es6:
источник
Node.prototype.toJSON = function() { return 'whatever you think that is right'; };
(если вы хотите что-то более общее / конкретное, просто попробуйте что-нибудь в дереве прототипа: HTMLDivElement реализует реализации HTMLElement Элемент реализует, Node реализует EventTarget, обратите внимание: это может зависеть от браузера, предыдущее дерево верно для Chrome)var a={id:1}; JSON.stringify([a,a]);
cache
будет недоступен developer.mozilla.org/en-US/docs/Web/JavaScript/…В Node.js вы можете использовать util.inspect (object) . Он автоматически заменяет круглые ссылки на «[Круговой]».
Хотя встроенный (установка не требуется) , вы должны импортировать его
Чтобы использовать это, просто позвонитеТакже имейте в виду, что вы можете передать параметры объекта для проверки (см. Ссылку выше)
Пожалуйста, прочитайте и отдайте должное комментаторам ниже ...
источник
var util = require('util');
obj_str = util.inspect(thing)
, НЕ <s>garbage_str = JSON.stringify(util.inspect(thing))
</ s>Интересно, почему никто не выложил правильное решение со страницы MDN ...
Найденные значения должны храниться в наборе , а не в массиве (метод replacer вызывается для каждого элемента ), и нет необходимости пробовать
JSON.stringify
каждый элемент в цепочке, ведущей к циклической ссылке.Как и в принятом ответе, это решение удаляет все повторяющиеся значения , а не только круглые. Но по крайней мере это не имеет экспоненциальной сложности.
источник
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)
возвращаетсяundefined
в Chromeпросто делать
тогда в вашем файле JS
https://github.com/WebReflection/circular-json
ПРИМЕЧАНИЕ: я не имею ничего общего с этим пакетом. Но я использую это для этого.
Обновление 2020
Обратите внимание, что CircularJSON находится только в обслуживании, и его наследником является flatted .
источник
JSON
в принципе.Flatted.stringify({blah: 1})
результаты в[{"blah":1}]
) Я вижу, что кто-то пытался поднять проблему по этому поводу, и автор ругал их и закрывал проблему для комментариев.Мне очень понравилось решение Trindaz - более подробное, однако в нем были некоторые ошибки. Я установил их для тех, кто любит это тоже.
Кроме того, я добавил ограничение длины для своих объектов кэша.
Если объект, который я печатаю, действительно большой - я имею в виду бесконечно большой - я хочу ограничить свой алгоритм.
источник
Ответ @ RobW правильный, но он более производительный! Потому что он использует hashmap / set:
источник
{"a":{"b":{"a":"d"}}}
и даже удаляет узлы, имеющие пустой объект {}Обратите внимание, что есть также
JSON.decycle
метод, реализованный Дугласом Крокфордом. Смотрите его cycle.js . Это позволяет структурировать практически любую стандартную структуру:Вы также можете воссоздать оригинальный объект с помощью
retrocycle
метода. Таким образом, вам не нужно удалять циклы из объектов, чтобы их упорядочить.Однако это не будет работать для узлов DOM (которые являются типичной причиной циклов в реальных случаях использования). Например это бросит:
Я сделал ответвление, чтобы решить эту проблему (см. Мой fork.js ). Это должно работать нормально:
Обратите внимание, что в моем форке
JSON.decycle(variable)
работает так же, как в оригинале, и выдаст исключение, когдаvariable
содержат DOM-узлы / элементы.При использовании
JSON.decycle(variable, true)
вы принимаете тот факт, что результат не будет обратимым (ретроцикл не будет заново создавать узлы DOM). Элементы DOM должны быть в некоторой степени идентифицируемыми. Например, еслиdiv
элемент имеет идентификатор, он будет заменен строкой"div#id-of-the-element"
.источник
JSON.decycle(a, true)
что происходит, когда вы передаете true в качестве параметра для отмены функции.stringifyNodes
вариант верным в форке. Это сбросит например ,div
с идентификатором = «какой - то-идентификатор» в строку:div#some-id
. Вы избежите некоторых проблем, но вы не сможете полностью вернуться в цикл.Я бы порекомендовал проверить json-stringify-safe от @ isaacs-- он используется в NPM.
Установить:
Использовать:
Это дает:
источник
Для будущих гуглеров, которые ищут решение этой проблемы, когда вы не знаете ключей всех циклических ссылок, вы можете использовать оболочку вокруг функции JSON.stringify, чтобы исключить циклические ссылки. Смотрите пример сценария на https://gist.github.com/4653128 .
По сути, решение сводится к тому, чтобы сохранить ссылку на ранее напечатанные объекты в массиве и проверить ее в функции замены перед возвратом значения. Это более сжато, чем исключение только циклических ссылок, потому что оно также исключает возможность печати объекта дважды, одним из побочных эффектов которого является избегание циклических ссылок.
Пример оболочки:
источник
if(printedObjIndex)
когда должны писать,if(printedObjIndex==false)
потому чтоindex
также может быть0
переведено,false
если вы явно не укажете иначе.===
?0 == false
естьtrue
,0 === false
естьfalse
. ; ^) Но я бы предпочел не инициализироватьprintedObjIndex
как false, так как тогда вы можете проверить,undefined
чтобы вы (ну, Trindaz) не смешивали метафоры так странно.Используйте метод JSON.stringify с заменителем. Прочитайте эту документацию для получения дополнительной информации. http://msdn.microsoft.com/en-us/library/cc836459%28v=vs.94%29.aspx
Найдите способ заполнить массив замен циклическими ссылками. Вы можете использовать метод typeof, чтобы определить, имеет ли свойство тип «объект» (ссылка) и точную проверку на равенство (===) для проверки циклической ссылки.
источник
var obj = {foo:obj}
это не создает циклическую ссылку. Вместо этого он создает объект,foo
атрибут которого ссылается на предыдущее значениеobj
(undefined
если не определено ранее, объявлено из-заvar obj
).Если
приводит к
Тогда вы можете напечатать так:
источник
оценивает:
с функцией:
источник
Я знаю, что это старый вопрос, но я хотел бы предложить созданный мной пакет NPM, называемый smart-циркуляр , который работает не так, как другие предложенные способы. Это особенно полезно, если вы используете большие и глубокие объекты .
Некоторые функции:
Замена циклических ссылок или просто повторяющихся структур внутри объекта путем, ведущим к его первому появлению (не только строкой [циклически] );
Посредством поиска округлостей в поиске в ширину пакет гарантирует, что этот путь будет как можно меньшим, что важно при работе с очень большими и глубокими объектами, где пути могут быть раздражающе длинными и трудными для отслеживания (выборочная замена в JSON.stringify делает DFS);
Позволяет персонализированные замены, удобные для упрощения или игнорирования менее важных частей объекта;
Наконец, пути написаны точно так, как необходимо для доступа к указанному полю, что может помочь при отладке.
источник
Второй аргумент JSON.stringify () также позволяет вам указать массив имен ключей, которые должны быть сохранены для каждого объекта, с которым он сталкивается в ваших данных. Это может работать не для всех вариантов использования, но является гораздо более простым решением.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
Примечание. Как ни странно, определение объекта из OP не выдает ошибку циклической ссылки в последних версиях Chrome или Firefox. Определение в этом ответе было изменено так , что он сделал выдаст ошибку.
источник
Чтобы обновить ответ переопределения способа работы JSON (возможно, не рекомендуется, но очень просто), не используйте
circular-json
(это устарело). Вместо этого используйте преемник, flatted:https://www.npmjs.com/package/flatted
Заимствовано из старого ответа выше @ user1541685, но заменено новым:
npm i --save flatted
тогда в вашем файле JS
источник
Я нашел библиотеку циркуляр-json на github, и она хорошо подошла для моей проблемы.
Некоторые полезные функции, которые я нашел полезными:
источник
Я решаю эту проблему следующим образом:
источник
_class: ClassName { data: "here" }
так, поэтому я добавил следующее правило.replace(/(\w+) {/g, '{ __ClassName__: "$1", ')
. В моем случае я пытался увидеть, как выглядит объект http-запроса.Я знаю, что этот вопрос старый и имеет много хороших ответов, но я публикую этот ответ из-за его нового вкуса (es5 +)
Показать фрагмент кода
источник
Хотя на этот вопрос был дан достаточный ответ, вы также можете явно удалить данное свойство перед тем, как выполнять строковое преобразование, используя
delete
оператор.оператор удаления
это избавит от необходимости создавать или поддерживать сложную логику для удаления циклических ссылок.
источник
источник
Другое решение для решения этой проблемы с такими объектами - использование этой библиотеки.
https://github.com/ericmuyser/stringy
это просто, и вы можете в несколько простых шагов решить эту проблему.
источник
Основываясь на других ответах, я получаю следующий код. Хорошо работает с круговыми ссылками, объектами с пользовательскими конструкторами.
От данного объекта, подлежащего сериализации,
Github Link - DecycledJSON
Пример использования 1:
Пример использования 2:
источник
Попробуй это:
источник
seen.push(value)
= -D не должно быть больше строк кода ? Нравитсяfor (var key in value) {value[key] = circular_replacer(value[key]);}
В моем решении, если вы столкнетесь с циклом, он не просто говорит «цикл» (или ничего), он говорит что-то вроде foo: см. Объект № 42 выше, и чтобы увидеть, куда указывает foo, вы можете прокрутить вверх и найти для объекта # 42 (каждый объект, когда он запускается, говорит объект # xxx с некоторым целым числом xxx)
Отрывок:
источник