JSON Toolkit

FAQ k syntaxi a formátům: komentáře, koncové čárky a přesnost

Shrnutí: Zda jsou komentáře povoleny, proč koncová čárka chybuje, zda klíče potřebují uvozovky, proč se 9007199254740993 mění – dvanáct závěrů, každý ověřený proti RFC 8259.

Začátečník~12 min čteníPublikováno 2026-10-30Aktualizováno 2026-10-30
Titulní obrázek článku FAQ k syntaxi a formátům

Stručně: pro cokoli, co překračuje hranici procesu, pište prostý JSON podle RFC 8259 – dvojité uvozovky, žádné komentáře, žádné koncové čárky, UTF-8 bez BOM; pro konfiguraci, která potřebuje komentáře, použijte JSONC nebo JSON5 a za běhu převeďte zpět; a celá čísla nad 2^53-1 serializujte na serveru jako řetězce.

Co mají tyto otázky společné: vypadají, že by „měly fungovat“, ale specifikace je ve skutečnosti velmi přísná.

1. Co se počítá za platný JSON

Jaký je rozdíl mezi JSON, JSON5 a JSONC?

Standardní JSON uznává jen řetězce v dvojitých uvozovkách a nepovoluje komentáře ani koncové čárky. JSON5 i JSONC na něm oba přidávají funkce:

Funkce JSON (RFC 8259) JSONC JSON5
Řetězce v dvojitých uvozovkách Podporováno Podporováno Podporováno
Řetězce v jednoduchých uvozovkách Nepodporováno Nepodporováno Podporováno
Komentáře Nepodporováno Podporováno Podporováno
Koncové čárky Nepodporováno Nepodporováno Podporováno
Klíče bez uvozovek Nepodporováno Nepodporováno Podporováno
Hexadecimální čísla Nepodporováno Nepodporováno Podporováno
NaN / Infinity Nepodporováno Nepodporováno Podporováno
Přípona souboru .json .jsonc .json5

Princip volby je jednoduchý: napříč hranicemi procesů vždy používejte standardní JSON, zatímco konfigurační soubory mohou používat JSONC nebo JSON5 podle toho, co podporuje váš editor. tsconfig.json a .vscode/settings.json mohou obsahovat komentáře, protože je editor parsuje jako JSONC; předání striktnímu JSON.parse však stále chybuje.

Může JSON obsahovat komentáře?

Ne. Gramatika RFC 8259 nemá produkci pro komentáře, takže jakékoli // nebo /* */ způsobí selhání parsování.

Pokud chcete v konfiguraci udržet vysvětlivky, existují tři alternativy:

{
  "_comment": "Následující časový limit je v milisekundách",
  "timeout": 3000,
  "retry": {
    "$doc": "Počet opakování, 0 znamená žádné opakování",
    "count": 3
  }
}
  • Použijte konvenční pole jako _comment, která čtenář prostě ignoruje;
  • Použijte pole s prefixem $, abyste snížili pravděpodobnost kolize s obchodními poli;
  • Prostě pro konfiguraci přejděte k JSONC nebo YAML a za běhu převeďte na standardní JSON.

Proč koncová čárka způsobuje chybu?

Protože v gramatice jsou pole i objekty strukturami „prvek + oddělovač“ a za posledním prvkem není čárka povolena.

{
  "a": 1,
  "b": 2,
}

Úryvek výše má čárku navíc před }, a chyba se obvykle hlásí u čárky nebo u uzavírací závorky podle implementace parseru. Je to také nejjednodušší past při migraci z JavaScriptu – objektové literály v JS koncové čárky povolují, JSON ne.

Jsou jednoduché uvozovky povoleny?

Ne. Řetězce musí používat dvojité uvozovky; 'text' je syntaktická chyba.

Pokud byla data zkopírována z Pythoního repr(), ze shellového skriptu nebo ručně psané konfigurace, nejprve je převeďte nástrojem, místo abyste doufali, že parser je benevolentní.

Mohou být klíče bez uvozovek?

Ne. Názvy členů objektu musí být řetězce v dvojitých uvozovkách.

{ name: "json" }

To je objektový literál JavaScriptu, nikoli JSON. Přidání uvozovek ho zplatní:

{ "name": "json" }

Může být nejvyšší úrovní pole nebo řetězec?

Ano. RFC 8259 povoluje na nejvyšší úrovni jakoukoli hodnotu JSON: objekty, pole, řetězce, čísla, true, false i null jsou platné.

V inženýrské praxi se však doporučuje používat na nejvyšší úrovni pouze objekty nebo pole, ze dvou důvodů:

  1. Kompatibilita: starší parsery (z éry RFC 4627) vyžadují, aby nejvyšší úrovní byl objekt nebo pole;
  2. Bezpečnost: pole na nejvyšší úrovni historicky neslo riziko JSON hijacking. Moderní prohlížeče to opravily, ale starší systémy stále předpokládají konvenci.

Takže "hello" je platný JSON a ["a", "b"] také, ale API vracející {"data": [...]} je bezpečnější.

2. Kódování a řetězce

Rozbíjí BOM na začátku souboru parsování?

Ano. RFC 8259 výslovně vyžaduje, aby byl text JSON přenášen jako UTF-8 a nesmí přidávat byte order mark (BOM).

BOM jsou tři bajty EF BB BF na úplném začátku souboru. Je zcela neviditelný, ale zaujímá první pozici řetězce, takže parser usoudí, že „první znak není {“, a chybuje – a hlášený řádek a sloupec jsou obvykle řádek 1, sloupec 1, což vypadá matoucně.

„Uložit jako UTF-8“ v Poznámkovém bloku Windows ve výchozím nastavení zahrnuje BOM. Jak ho zkontrolovat a odstranit:

# Kontrola: výstup začínající efbbbf znamená přítomný BOM
head -c 3 data.json | xxd

# Odstranění: přeskočte první 3 bajty pomocí tail
tail -c +4 data.json > clean.json

Moderní JSON.parse v JavaScriptu BOM toleruje (V8 ho interně přeskakuje), ale striktní implementace v Javě, Go a Pythonu ne, což je častý důvod, proč „stejný soubor dává v různých jazycích různé výsledky“.

Mají se čínské znaky převádět na \uXXXX?

Ne. RFC 8259 vyžaduje, aby text JSON byl UTF-8, takže čínština může být přímo; {"name": "张三"} je naprosto platný.

\uXXXX je jen ekvivalentní alternativní zápis, používaný pro kanály, které znak neumí reprezentovat přímo. Pravidlo palce:

  • Těla HTTP požadavků, soubory, databáze: pište čínštinu přímo, ušetříte 3 bajty na znak;
  • HTTP hlavičky, parametry URL, vnoření do jiného řetězce: použijte escape sekvence, abyste se vyhnuli problémům s kódováním.

Jediné znaky, které musí být escapovány, jsou řídicí znaky (U+0000 až U+001F). Například zalomení řádku se musí zapsat jako \n; uvnitř řetězce nelze mít skutečné zalomení řádku.

Může emoji jít přímo do řetězce?

Ano, ale pamatujte, že zabírá dvě kódové jednotky UTF-16.

Emoji a mnoho vzácných znaků (například 𠮷) leží mimo BMP, takže v JavaScriptu je "😀".length === 2. Validace podle počtu znaků se proto snadno pokazí:

const text = "😀";
console.log(text.length);          // 2, počet kódových jednotek UTF-16
console.log([...text].length);     // 1, počet kódových bodů
console.log(Buffer.byteLength(text)); // 4, počet bajtů UTF-8

Pokud se limit délky přezdívky počítá pomocí .length, jedno emoji spotřebuje dva sloty; pokud backend počítá bajty, jsou to čtyři. Při slaďování definic jasně uveďte, zda máte na mysli kódové body, kódové jednotky, nebo bajty.

3. Čísla a speciální hodnoty

Proč se velké celé číslo 9007199254740993 změnilo na 9007199254740992?

Protože JSON.parse v JavaScriptu převádí čísla na plovoucí čísla IEEE 754 s dvojitou přesností a největší bezpečné celé číslo je 2^53-1.

Number.MAX_SAFE_INTEGER === 9007199254740991  // true
9007199254740993                              // skutečně vrací 9007199254740992

Jakékoli číslo nad 2^53-1 může být v posledních číslicích zaokrouhleno. Typickými oběťmi jsou 19ciferná ID uživatelů generovaná snowflake algoritmy, čísla objednávek a nanosekundová časová razítka.

Tři opravy, seřazené podle preferencí:

  1. Serializujte ID na serveru jako řetězec: "id": "9007199254740993", čímž problém přesnosti odstraníte u kořene;
  2. Použijte knihovnu pro bezztrátové parsování: náhrady JSON.parse umí velká celá čísla uchovat doslovně, například json-bigint;
  3. Pro zobrazení extrahujte regulárním výrazem: neparsujte celý dokument, jen vyhledejte cílové pole jako text.

Pozor, JSON.stringify má symetrický problém: číslo mimo rozsah bezpečných celých čísel už po serializaci nemusí nést původní hodnotu.

Může NaN a Infinity jít do JSON?

Ne. Produkce čísel v JSON povoluje jen desetinný zápis a NaN, Infinity a -Infinity nejsou platné hodnoty JSON.

Přístup JavaScriptu je „tichá degradace“:

JSON.stringify({ value: NaN });        // '{"value":null}'
JSON.stringify({ value: Infinity });   // '{"value":null}'

Žádná chyba, NaN se prostě stane null. Je to klasická scéna, kdy „frontend poslal NaN a backend dostal null“. Když potřebujete takovou sémantiku sdělit, vyjádřete ji explicitně řetězci nebo dohodnutými sentinelovými hodnotami:

{ "ratio": null, "ratioState": "not-a-number" }

Může se číslo psát jako 1e3 nebo 0.5?

Ano. Čísla JSON podporují desetinná místa a exponenty, takže 1e3, 1E3, 0.5 a -0.5 jsou platné.

Existují však omezení:

  • Nesmějí začínat ani končit .: .5 i 5. jsou neplatné, takže pište 0.5 a 5;
  • Žádné úvodní nuly: 01 je neplatné;
  • Žádné hexadecimální číslo: 0x1F je neplatné, to je rozšíření JSON5;
  • -0 je platné, ale JSON.stringify(-0) vypíše 0, čímž znaménko ztratí.

4. Sémantika objektů

Co se stane s duplicitními klíči?

Chování je definováno implementací; RFC 8259 jen říká, že názvy klíčů „mají“ být jedinečné, a nespecifikuje, co se stane u duplicit.

V praxi naprostá většina implementací bere poslední hodnotu:

JSON.parse('{"a":1,"a":2}')  // { a: 2 }

Ale nelze se na to spoléhat. Některé Java knihovny, encoding/json v Go a json v Pythonu se mezi verzemi liší: některé berou první hodnotu, některé chybují a některé berou poslední. Považovat duplicitní klíče za chybu je napříč jazyky nejbezpečnější přístup.

Duplicitní klíče nenajdete zrakem – ve zminifikovaném JSON může být stejný klíč tisíce znaků daleko. Použijte skript:

# Vytáhněte klíče, které se na stejné úrovni vyskytují vícekrát, jako hrubou kontrolu
jq -r 'paths(scalars) | join(".")' data.json | sort | uniq -d

Čím se stane undefined?

Záleží, a toto je nejnáchylnější místo ke chybám:

JSON.stringify({ a: undefined });              // '{}'  klíč se úplně zahodí
JSON.stringify({ a: undefined, b: 1 });        // '{"b":1}'
JSON.stringify([undefined]);                   // '[null]'  uvnitř polí se stane null
JSON.stringify({ a: function () {} });         // '{}'  funkce se také zahazují

Stejné undefined znamená uvnitř objektu „pole zmizí“ a uvnitř pole „stane se null“. Pokud backend bere různé větve pro „pole chybí“ a „pole je null“, dostanete tady nekonzistenci.

Když potřebujete vyjádřit „žádná hodnota“ explicitně, použijte null, nikoli undefined.

Co se stane po parsování {"__proto__": {...}}?

JSON.parse sám je bezpečný: __proto__ se považuje za obyčejnou vlastní vlastnost a prototyp nemění.

Nebezpečná je operace sloučení po parsování:

const patch = JSON.parse('{"__proto__": {"isAdmin": true}}');
Object.assign({}, patch);       // některé implementace znečistí prototyp

Správný přístup je iterovat vlastní vlastnosti a přeskočit __proto__, constructor a prototype. Podrobnosti najdete v FAQ k výkonu a bezpečnosti.

5. Rychlý přehled

Syntaxe Platné Poznámky
{"a": 1,} Ne Koncová čárka
{'a': 1} Ne Jednoduché uvozovky
{a: 1} Ne Klíč bez uvozovek
{"a": 1} // comment Ne Komentáře
"hello" Ano Řetězec na nejvyšší úrovni je platný, ale v API se používá zřídka
{"a": 1e3} Ano Exponenty jsou podporovány
{"a": 01} Ne Úvodní nula
{"a": NaN} Ne Neplatný literál; stringify ho změní na null
\uFEFF{"a":1} Ne BOM není součástí textu JSON
{"a":1,"a":2} Sporné Implementace berou poslední hodnotu, ale nespoléhejte se na to