JSON-Diff
Сравните два JSON-документа и увидите, какие именно поля добавлены, удалены или изменены
JSON A (слева / до)
JSON B (справа / после)
JSON-Diff
Сравните два JSON-документа и увидите, какие именно поля добавлены, удалены или изменены
Возможности
- Структурный diff между двумя JSON-значениями — объекты, массивы и примитивы корректно обходятся (null трактуется как скаляр, а не объект; баг typeof null исправлен)
- Каждое различие сообщается как путь RFC 6901 JSON Pointer (напр. `/users/0/email`), позволяя сразу перейти к точному узлу во вложенных данных
- Изменённые записи показывают значения «до» И «после» рядом, так что очевидно, переключился ли 'active' с true→false или изменилось число
- Сводка: добавлено, удалено, изменено и неизменные листья — масштаб diff одним взглядом перед чтением деталей по путям
- Раздельный отчёт об ошибке разбора по стороне называет, какой ввод не разобрался, и включает сообщение движка JavaScript — не нужно угадывать, A или B повреждён
- Кнопка «Копировать отчёт» выдаёт весь diff (разделы «Добавлено» / «Удалено» / «Изменено» плюс счётчик неизменных) как простой текст — вставьте в код-ревью или сообщение коммита
- «Загрузить пример» заполняет обе панели маленьким реалистичным примером (запись пользователя с изменениями роли + адреса), новые пользователи видят diff без набора текста
- Полностью на стороне клиента: JSON A и JSON B парсятся и сравниваются в вашем браузере; ничего не загружается, и инструмент работает офлайн после загрузки страницы
Как использовать
- Вставьте JSON «до» в левое текстовое поле (JSON A), JSON «после» — в правое (JSON B).
- Нажмите «Сравнить». Diff рассчитывается рекурсивно: объекты — по ключу, массивы — по индексу.
- Прочтите сводку: сколько ключей добавлено, удалено, изменено и сколько листьев совпало.
- Прокрутите списки по путям, чтобы увидеть, какие пути JSON Pointer изменились; изменённые строки показывают «до» → «после».
- Нажмите «Копировать отчёт», чтобы получить весь diff простым текстом — удобно для заметок ревью, баг-репортов и сообщений коммитов.
- Используйте «Загрузить пример», чтобы увидеть рабочий пример перед вставкой своих данных.
Советы и лучшие практики
- Сначала прогоните обе стороны через JSON Formatter, если хотите, чтобы текстовый diff тоже считал структурно равные документы без изменений.
- Для больших массивов с важным порядком этот инструмент подходит идеально; для множеств — предварительно отсортируйте по стабильному ключу.
- Вывод пути — RFC 6901, его можно передать напрямую в библиотеки вроде fast-json-patch для программного применения изменений.
- Вставляйте отчёт в описания PR, чтобы показать ревьюерам, что именно изменилось в JSON конфига или фикстуры.
- Если ошибки разбора указывают на конкретную колонку, сообщение движка часто включает строку/колонку у парсеров типа json5 — здесь же используется строгий JSON.parse, поэтому строка/колонка — от хоста.
Вопросы и ответы
Как сравниваются массивы — по индексу или по значению?
По индексу. Элемент 0 A сравнивается с элементом 0 B, 1 с 1 и т. д. Если A длиннее, лишние хвостовые индексы помечаются как «Удалено»; если B длиннее — как «Добавлено». Быстро и предсказуемо, но единичная вставка в начале большого массива каскадирует во множество «изменено». Для нечувствительных к порядку сравнений (множества уникальных ID) сначала отсортируйте оба массива или преобразуйте в объекты с ключом-идентификатором.
Какая нотация путей в результате?
RFC 6901 JSON Pointer: пути — это токены, разделённые слешами, спускающиеся по дереву JSON. `/users/0/email` означает «свойство email элемента 0 в users». Ключи с `~` экранируются как `~0`, слеши — `~1`. Сам корень — `/`. Та же нотация используется в патч-инструментах, JSON Schema instancePath и в подсказке указателя json-formatter.
Как обрабатывается null?
null трактуется как листовое значение, не как объект — хотя в JavaScript typeof null === 'object'. Так {a: null} vs {a: {}} показывается как изменённое, а не рекурсирует в пустой объект. {a: null} vs {a: null} — один неизменный лист, а {a: null} vs {a: 0} — изменённое с «до=null после=0».
Diff обрабатывает ключи со специальными символами?
Да. Ключи, содержащие точки, слеши, скобки или тильды, экранируются по JSON Pointer в выводе пути — `~` становится `~0`, `/` — `~1`. Так ключ с буквальным именем `a/b` показывается как `/a~1b` — однозначно обратимо.
Почему счёт неизменных не соответствует моим ожиданиям?
Неизменные считаются на уровне ЛИСТЬЕВ — примитивы, равные между A и B. Глубоко вложенный объект, чьё поддерево полностью идентично, даёт по одной неизменной записи на лист, а не одну на всё поддерево. Это делает счётчик настоящей проверкой: «сколько примитивных значений осталось прежними».
Что если одна сторона null или пуста?
Пустой ввод парсится как null (так `{a:1}` vs пусто сравнивается с null и весь объект помечается как добавленный). Литеральный `null` — валидный JSON-документ; сравнение двух null даёт ноль добавленных/удалённых/изменённых и один неизменный. Если оба пусты — diff тривиально нулевой везде.
Мой JSON куда-то отправляется?
Нет. Оба текстовых поля остаются в вашем браузере; diff работает в том же JavaScript-контексте, что и страница. Вкладка «Сеть» в DevTools не показывает запросов при нажатии «Сравнить». Инструмент работает офлайн после кеширования страницы.
Чем это отличается от построчного текстового diff?
Текстовый diff вроде `diff a.json b.json` работает с символами и переводами строк: переформатируете те же данные — он подсветится. Это СТРУКТУРНЫЙ diff: `{"a":1, "b":2}` и `{"b":2, "a":1}` идентичны (ноль diff). Также не учитывает отступы, концевые пробелы и стили комментариев. Используйте текстовый diff, когда важно форматирование; этот — когда важны данные.