Geonode logo
Geonode Team

Geonode Team

Mis à jour : 7 octobre 2026

Publié : 2 septembre 2026

JSON.parse() en JavaScript : un guide complet

`JSON.parse()` transforme une chaîne de caractères en une valeur JavaScript. C'est là toute l'API, et il suffit d'une dizaine de secondes pour la maîtriser. Ce qui est intéressant, c'est tout ce qui l'entoure : la fonction « reviver », la perte de précision numérique qui se glisse discrètement dans l'environnement de production, le cas particulier de « `__proto__` », ainsi que le récent ajout à la norme qui permet enfin de voir le texte source d'origine. Ce guide aborde tous ces aspects, en mettant l’accent sur les modes de défaillance plutôt que sur le scénario idéal.

Une petite précision sur la raison pour laquelle une entreprise spécialisée dans les proxys aborde le sujet de JSON.parse. Nous sommes Geonode et nous vendons des proxys ; l’SyntaxError la plus courante signalée par nos clients n’a absolument rien à voir avec JSON : il s’agit de « Unexpected token '<' », ce qui signifie que la réponse était au format HTML plutôt que JSON, et donc que l’API a renvoyé une page de blocage, une redirection vers la page de connexion ou une page d’erreur. Voici donc une mise en garde honnête : si JSON.parse s’affiche sur les données que vous avez récupérées, enregistrez le corps brut de la réponse avant de modifier quoi que ce soit d’autre. Neuf fois sur dix, l’analyseur fonctionne parfaitement et signale à juste titre qu’une page web vous a été envoyée. L’achat de proxys ne résout ce problème que dans le cas spécifique où vous avez été bloqué ; cela ne change rien en cas d’URL erronée, de jeton expiré ou de limite de débit que vous devriez respecter. Affichez d’abord la réponse.

Cela étant dit, passons à l’API proprement dite.

Les bases et les erreurs que vous rencontrerez réellement

const data = JSON.parse('{"name": "Ada", "born": 1815}');
// { name: "Ada", born: 1815 }

Deux paramètres : le texte et une fonction de restauration facultative. C’est tout.

Elle lève une exception ``SyntaxError`

` lorsque l’entrée ne respecte pas la grammaire JSON, et celle-ci est plus stricte que la syntaxe des littéraux d’objets JavaScript, ce qui peut prendre les utilisateurs au dépourvu. Quatre cas de figure expliquent la quasi-totalité des échecs.

Les guillemets simples. MDN est clair : « Les chaînes JSON doivent être délimitées par des guillemets doubles (et non simples). » Valide en JavaScript, invalide en JSON.

JSON.parse("{'name': 'Ada'}");  // SyntaxError
JSON.parse('{"name": "Ada"}');  // fine

Les virgules de fin. Autorisées en JavaScript moderne, interdites en JSON :

JSON.parse("[1, 2, 3, 4, ]");  // SyntaxError

Les clés non entre guillemets. {name: "Ada"}

C'est un littéral d'objet correct, mais pas du JSON. Les clés doivent être des chaînes entre guillemets.

La réponse n'était pas au format JSON. Celle décrite ci-dessus. Unexpected token '<'

signifie que le corps commençait par <

, ce qui indique du HTML. Unexpected end of JSON input

signifie généralement un corps vide — un code 204, une réponse tronquée ou une requête fetch que vous avez oublié d'attendre.

Enveloppez-la, systématiquement, et consignez ce que vous avez réellement reçu :

function parseOrThrow(text, url) {
  try {
    return JSON.parse(text);
  } catch (err) {
    throw new Error(
      `Failed to parse JSON from ${url}: ${err.message}. ` +
      `First 200 chars: ${text.slice(0, 200)}`
    );
  }
}

La partie text.slice(0, 200)

est celle qui importe. Un simple SyntaxError

indique que l’analyse a échoué ; les 200 premiers caractères vous expliquent pourquoi, et la réponse est généralement visible immédiatement.

La fonction « Reviver » et son utilité

Le deuxième argument transforme les valeurs au fur et à mesure de leur analyse :

const data = JSON.parse(text, (key, value) => {
  if (key === "created") return new Date(value);
  return value;
});

Trois comportements qu’il convient de bien connaître.

Elle s’exécute en profondeur. Les propriétés imbriquées sont traitées avant leurs parents, et l’appel final utilise une chaîne vide comme clé pour la valeur racine. Ainsi, lorsque votre reviver rencontre un objet, ses enfants ont déjà été traités.

**Le fait de renvoyer « undefined

» supprime la propriété.** MDN : « Si la fonction reviver

renvoie undefined

(ou ne renvoie aucune valeur), la propriété est supprimée de l’objet. » Il est facile de déclencher cela par accident : un reviver comportant une branche conditionnelle qui aboutit à la fin de la liste renvoie undefined

et supprime silencieusement des clés. Renvoyez toujours explicitement value

par défaut.

La racine peut être entièrement remplacée. « Si vous renvoyez une autre valeur à partir de reviver

, cette valeur remplacera complètement la valeur initialement analysée. Cela s’applique même à la valeur racine.»

L’utilisation classique est la restauration de dates, puisque JSON ne dispose pas de type de date :

const ISO_DATE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/;

const data = JSON.parse(text, (key, value) =>
  typeof value === "string" && ISO_DATE.test(value)
    ? new Date(value)
    : value
);

Soyez prudent avec la correspondance de motifs. Un reviver qui convertit tout ce qui ressemble à une date convertira également les chaînes que vous souhaitiez conserver en tant que telles — numéros de version, identifiants, contenu utilisateur qui ressemble par hasard à un horodatage. Privilégiez la correspondance sur le nom de la clé lorsque vous connaissez le schéma.

Notez également le coût : le reviver est appelé une fois par valeur dans le document. Sur des charges utiles volumineuses, cela représente un véritable enjeu de performances, et il est souvent plus économique de parser simplement le document, puis de ne transformer par la suite que les champs qui vous intéressent.

Accès au texte source : context.source et JSON.rawJSON

Il s'agit de l'ajout le plus important de ces derniers temps, et de nombreux développeurs ne l'ont pas encore découvert.

La proposition d’accès au texte source via JSON.parse a atteint le stade 4 du processus TC39, ce qui signifie qu’elle est approuvée pour la norme. Elle résout un problème que la proposition énonce clairement : « La transformation entre les valeurs ECMAScript et le texte JSON entraîne des pertes. »

La fonction reviver reçoit désormais un troisième argument pour les valeurs primitives. MDN décrit ``context.source`

comme « la chaîne JSON d’origine représentant cette valeur » — et la proposition est plus précise, la qualifiant de texte source « incluant la ponctuation mais excluant les espaces non significatifs en début et en fin de chaîne », aux côtés de ``index

, ``input

et ``keys

`.

Un exemple suffit à comprendre l’importance de cette distinction :

const text = '{"id": 9007199254740993}';

JSON.parse(text).id;
// 9007199254740992  — wrong, silently

JSON.parse(text, (key, value, context) =>
  key === "id" ? BigInt(context.source) : value
).id;
// 9007199254740993n  — correct

Sans accès à la source, le nombre a déjà été converti en nombre double JavaScript au moment où votre reviver le détecte. La précision a disparu avant même que vous ne puissiez intervenir. context.source

vous fournit les chiffres d’origine.

La proposition ajoute également JSON.rawJSON()

, qui vous permet de fournir du texte JSON brut que JSON.stringify

renvoie tel quel — bouclant ainsi la boucle afin qu’un BigInt lu à partir de JSON puisse être réécrit sans altération.

JSON.stringify({ id: JSON.rawJSON("9007199254740993") });
// '{"id":9007199254740993}'

Vérifiez la prise en charge de vos environnements cibles avant de vous y fier, mais il s’agit désormais de la solution adéquate au problème des grands nombres, et non plus d’une simple solution de contournement.

La précision des nombres : le bug que vous risquez de livrer

Ce sujet mérite une section à part entière, car il se produit de manière silencieuse et ses symptômes apparaissent loin de la cause réelle.

Les nombres JSON sont convertis en nombres JavaScript, qui sont des nombres à virgule flottante de type double selon la norme IEEE 754. Les entiers supérieurs à Number.MAX_SAFE_INTEGER — soit 9 007 199 254 740 991 — ne peuvent pas tous être représentés avec exactitude. MDN le dit clairement : les nombres « peuvent perdre en précision au cours du processus ».

Le danger réside dans le fait qu’aucune exception n’est levée. Vous obtenez un nombre. Mais ce n’est tout simplement pas le nombre qui a été envoyé.

JSON.parse('{"id": 12345678901234567890}').id;
// 12345678901234567000

Concrètement, cela pose problème dans les cas suivants :

  • Identifiants de base de données. Les clés primaires de type entier 64 bits dépassent la plage de sécurité. Deux enregistrements distincts peuvent être convertis en un même nombre JavaScript.
  • Les identifiants de type « Snowflake ». Utilisés par plusieurs grandes plateformes, ils dépassent systématiquement la limite.
  • Les montants financiers en unités mineures. Les sommes importantes en centimes ou en satoshis.
  • Les horodatages en nanosecondes. Toute valeur d’époque en nanosecondes depuis 1970 se situe déjà en dehors de la plage de sécurité.

Trois solutions, par ordre de préférence :

Demander des chaînes de caractères. Si vous contrôlez l’API, sérialisez les identifiants volumineux sous forme de chaînes de caractères. C’est la solution la plus propre, elle fonctionne partout et ne coûte rien. MDN recommande précisément cela : « Une façon de transférer de grands nombres sans perte de précision consiste à les sérialiser sous forme de chaînes de caractères, puis à les reconvertir en BigInts. »

Utilisez l’context.sourcee avec un convertisseur. Comme ci-dessus, lorsque vous ne contrôlez pas le producteur et que votre environnement le prend en charge.

Utilisez une bibliothèque JSON prenant en charge les BigInt. Pour les environnements plus anciens, plusieurs analyseurs syntaxiques gèrent cela. Cela implique une dépendance et un léger impact sur les performances.

Ce qui ne fonctionne pas : vérifier si le nombre « a l’air correct » après l’analyse. À ce stade, l’information a été perdue, et il est impossible de distinguer une valeur erronée d’une valeur correcte.

« __proto__ » et la pollution du prototype

MDN identifie le seul cas où JSON et JavaScript divergent en termes de signification : « Le seul cas où un texte JSON représente une valeur différente de celle de la même expression JavaScript concerne la clé « \"__proto__\" ». »

Dans un littéral d’objet JavaScript, __proto__ définit le prototype. Dans JSON.parse, cela crée une propriété propre ordinaire : `

const fromLiteral = { __proto__: { admin: true } };
fromLiteral.admin;             // true — prototype was set

const fromJson = JSON.parse('{"__proto__": {"admin": true}}');
fromJson.admin;                // undefined — plain own property
Object.hasOwn(fromJson, "__proto__");  // true

Ainsi, JSON.parse en soi est sans danger ici — il s’agit d’un comportement délibéré et correct.

Le danger réside dans ce qui se passe ensuite. Les vulnérabilités liées à la pollution des prototypes surviennent presque toujours lorsque des données analysées sont fusionnées dans un autre objet par du code qui ne filtre pas les clés dangereuses :

// Unsafe: a naive deep merge can walk into Object.prototype
function merge(target, source) {
  for (const key in source) {
    if (typeof source[key] === "object") {
      merge(target[key] ?? (target[key] = {}), source[key]);
    } else {
      target[key] = source[key];
    }
  }
}

Envoyez une charge utile contenant __proto__ et vous pourrez modifier Object.prototype pour l’ensemble du programme. Mesures de protection :

Filtrez explicitement les clés dangereuses — __proto__, constructor, prototype — dans toute fusion ou affectation impliquant des données non fiables.

Utilisez Object.create(null) pour les objets contenant des clés non fiables, afin qu’il n’y ait pas de prototype à polluer.

Utilisez Map lorsque vous créez réellement un magasin de paires clé-valeur plutôt qu’un objet structuré.

Validez par rapport à un schéma. C’est la réponse générale, qui permet également de détecter d’autres problèmes. L’analyse syntaxique et la validation sont des étapes distinctes, et toutes deux sont nécessaires.

JSON.parse vs eval vs Response.json()

N'utilisez jamais eval. Cette méthode exécute du code arbitraire, elle est plus lente pour cet usage et accepte des données qui ne sont pas au format JSON. Il n'existe aucun cas où eval soit l'outil approprié pour analyser du JSON.

Response.json() est ce qu'il vous faut lorsque vous travaillez avec fetch. Elle lit le corps de la requête et l'analyse en une seule étape :

const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();

La vérification res.ok est la partie que les gens ont tendance à ignorer, et c’est justement cette omission qui est la cause directe de l’erreur « Unexpected token '<' » mentionnée dans l’introduction. fetch ne rejette pas les statuts d’erreur HTTP — un 403 ou un 500 se résout normalement, puis .json() tente d’analyser une page d’erreur. Vérifiez d’abord le statut, et consultez content-type si vous souhaitez être rigoureux :

const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status} from ${url}`);
const type = res.headers.get("content-type") ?? "";
if (!type.includes("application/json")) {
  const body = await res.text();
  throw new Error(`Expected JSON, got ${type}: ${body.slice(0, 200)}`);
}
const data = await res.json();

Notez que Response.json() n’accepte pas de « reviver ». Si vous en avez besoin, utilisez res.text() suivi de JSON.parse.

Les bibliothèques diffèrent également sur ce point : certaines effectuent l’analyse automatiquement et lèvent une exception en cas de statuts autres que 2xx, ce qui modifie l’emplacement où votre gestion des erreurs doit être placée. Nous avons comparé ce comportement dans axios vs fetch.

Analyser un fichier JSON volumineux sans bloquer la page

JSON.parse est une opération synchrone et bloquante. Sur le thread principal, l’analyse d’un document volumineux bloque l’interface pendant toute sa durée — il s’agit d’une cause courante et facile à diagnostiquer de saccades.

Règle générale : en dessous d’un mégaoctet, ne vous en préoccupez pas. Entre un et dix mégaoctets, effectuez des tests sur votre appareil cible le plus lent. Au-delà de dix mégaoctets, optez pour une autre solution.

Les options, par ordre croissant d’effort :

Déplacez l’opération vers un Web Worker. La solution la plus simple et la plus efficace. Effectuez l’analyse en dehors du thread principal, puis renvoyez le résultat. Notez que le transfert du résultat a son propre coût lié à la clonation de la structure ; cette solution est donc particulièrement utile lorsque le worker effectue également le traitement ultérieur.

Demandez moins de données. Pagination, sélection de champs, point de terminaison plus restreint. C’est presque toujours la bonne solution, mais elle est presque toujours ignorée car elle nécessite de contacter le propriétaire de l’API.

Utiliser un analyseur en continu. Il existe des bibliothèques qui émettent les valeurs au fur et à mesure de leur arrivée plutôt que de construire l’arborescence entière. Cela en vaut la peine lorsque les documents sont vraiment volumineux ou lorsque vous n’avez besoin que d’une partie de la charge utile.

Utiliser du JSON délimité par des sauts de ligne. Pour les grandes collections, un document JSON par ligne est nettement plus facile à traiter de manière incrémentielle, car chaque ligne est analysée indépendamment et un flux tronqué produit tout de même des enregistrements complets. Si vous contrôlez le format, c’est souvent la meilleure solution — et les compromis par rapport à d’autres formats sont abordés dans notre comparaison entre JSON et CSV.

Quand l’JSON.parse, n’est pas l’outil adéquat

Lorsque les données d’entrée ne sont pas au format JSON. JSON5, JSONC et les fichiers de configuration contenant des commentaires ou des virgules de fin nécessitent tous leurs propres analyseurs syntaxiques. JSON.parse les rejettera correctement et vous ne devriez pas tenter de supprimer les commentaires à l’aide d’une expression régulière — cette approche vous mènerait à développer un analyseur syntaxique que vous n’aviez pas l’intention d’écrire.

Lorsque vous avez besoin d’une validation, et pas seulement d’un analyse syntaxique. Une analyse syntaxique réussie vous indique que la syntaxe était valide. Elle ne dit rien sur l’existence des champs obligatoires ni sur le fait qu’ils aient les bons types. Analysez puis validez ; une bibliothèque de validation de schéma est l’outil adapté pour la deuxième étape, contrairement à try/catch.

Lorsque les données doivent faire l’aller-retour sans perte. Les grands nombres entiers, les dates, les undefined, les fonctions, les Map, les Set, les NaN, les Infinity — aucun ne survit intact au format JSON. Si un aller-retour sans perte est une exigence, utilisez délibérément context.source et JSON.rawJSON, ou optez pour un format conçu à cet effet.

Lorsque vous effectuez une analyse à chaque rendu. Analyser la même chaîne de caractères à plusieurs reprises dans un chemin d’accès très sollicité est un pur gaspillage. Analysez-la une seule fois et mettez-la en cache.

Lorsque la chaîne provient d’une requête que vous n’avez pas vérifiée. Le cas avec lequel nous avons commencé, que nous rappelons ici car c’est le plus courant de tous. Si JSON.parse lève une exception sur les données récupérées, le bug se trouve en amont. Vérifiez le code d’état, vérifiez le type de contenu, consignez le corps de la requête. L’analyseur vous dit la vérité.

Questions fréquentes

À quoi sert la méthode JSON.parse ?

Elle convertit une chaîne au format JSON en une valeur JavaScript : objet, tableau, chaîne, nombre, booléen ou null. Elle accepte une fonction de « reviver » facultative qui permet de transformer chaque valeur au fur et à mesure de son analyse. Elle lève une exception « SyntaxError » si l'entrée n'est pas au format JSON valide.

Pourquoi JSON.parse affiche-t-il le message « Token inattendu '<' » ?

Parce que la chaîne commence par <, ce qui signifie que vous avez reçu du code HTML plutôt que du JSON — généralement une page d’erreur, une redirection de connexion ou une page de blocage. L’analyseur fonctionne correctement ; c’est la requête qui pose problème. Enregistrez les 200 premiers caractères du corps de la réponse : la cause est généralement évidente.

Comment analyser du JSON contenant de grands nombres en JavaScript ?

Utilisez l’argument context.source de la fonction reviver pour lire les chiffres d’origine et construire un objet BigInt, car au moment où la valeur atteint votre reviver, elle a déjà perdu en précision. Mieux encore, si vous contrôlez l’API, sérialisez les grands identifiants sous forme de chaînes de caractères.

Qu’est-ce que la fonction « reviver » dans JSON.parse ?

Il s’agit d’un deuxième argument facultatif appelé pour chaque paire clé-valeur, en profondeur, et se terminant par la racine sous une clé de type chaîne vide. Tout ce qu’il renvoie remplace la valeur ; renvoyer « undefined » supprime la propriété. Son rôle habituel est de convertir des chaînes de caractères en types plus riches tels que « Date ».

JSON.parse est-il sûr ?

En ce qui concerne l’exécution de code, oui — contrairement à eval, il n’exécute jamais rien. Il gère également __proto__ en toute sécurité, en créant une propriété propre simple plutôt qu’en définissant le prototype. Le risque réside dans ce que vous faites ensuite : fusionner des données analysées non fiables dans d’autres objets sans filtrer __proto__ et constructor, c’est ainsi que se produit la pollution du prototype.

Quelle est la différence entre JSON.parse et Response.json() ?

Response.json() lit le corps d’une réponse fetch et l’analyse en une seule étape ; cette méthode n’accepte pas de « reviver ». JSON.parse fonctionne sur une chaîne de caractères dont vous disposez déjà. Notez que fetch ne rejette pas les erreurs HTTP ; vérifiez donc res.ok avant d’appeler .json(), sinon vous analyserez une page d’erreur.

JSON.parse prend-il en charge les commentaires ou les virgules de fin ?

Non. Ces deux éléments ne sont pas valides en JSON et provoquent tous deux une exception « SyntaxError ». Si votre entrée en contient, il s’agit de JSON5 ou de JSONC, et vous aurez besoin d’un analyseur syntaxique adapté à ce format plutôt que d’une expression régulière qui les supprime.

JSON.parse bloque-t-il le thread principal ?

Oui, c’est une opération synchrone. Pour les documents de moins d’un mégaoctet, cela n’a pas d’importance ; pour les charges utiles volumineuses, cela provoque un gel visible de l’application. Déplacez l’analyse vers un Web Worker, demandez moins de données ou utilisez un analyseur en continu.

Conclusion : la fonction `

`JSON.parse`` possède une signature à deux paramètres et recèle une complexité surprenante. Les éléments à retenir sont ceux qui échouent discrètement plutôt que de manière flagrante.

La précision des nombres est le problème le plus grave : les grands entiers sont corrompus en silence, aucune exception n’est levée, et la valeur erronée est impossible à distinguer de la bonne jusqu’à ce qu’un problème survienne en aval. La solution consiste soit à utiliser des identifiants encodés sous forme de chaînes de caractères à la source, soit à utiliser l’argument context.source du reviver, qui en est désormais à la phase 4 et fait partie de la norme.

Le reviver mérite d’être davantage utilisé, en particulier pour les dates, avec toutefois cette mise en garde : oublier de renvoyer value sur le chemin par défaut supprime silencieusement des propriétés. Et la pollution des prototypes n’est absolument pas un problème d’JSON.parse — la fonction gère correctement __proto__ — mais c’est un problème pour tout ce qui fusionne le résultat, ce qui est suffisamment proche pour avoir de l’importance.

Tout le reste se résume à une seule habitude : lorsque l’analyse des données que vous avez récupérées échoue, consignez le corps brut dans un journal avant de modifier le code. Le message d’erreur contient presque toujours la réponse, et celle-ci est généralement que vous n’avez tout simplement jamais reçu de données JSON.