Aller au contenu principal
12 min de lecture

Pourquoi JavaScript affiche « [object Object] » et comment corriger ce problème

Comprendre l'affichage [object Object] en JavaScript : mécanisme de coercition, Object.prototype.toString, solutions concrètes avec JSON.stringify, console.log et fonctions utilitaires.

12 min de lecture
Partager
Pourquoi JavaScript affiche « [object Object] » et comment corriger ce problème

Toute personne qui a touché à JavaScript a déjà vu cette chaîne cryptique s’afficher dans un alert, une concaténation ou un rendu DOM : [object Object]. Pas un bug à proprement parler. Plutôt le résultat d’un mécanisme de conversion que le langage applique en coulisses, et que la plupart des développeurs découvrent par accident.

Cet article décortique le phénomène du début à la fin — du prototype chain à la sérialisation JSON — avec du code exécutable et des correctifs applicables immédiatement.

Ce que signifie [object Object] (en 30 secondes)

Quand JavaScript doit convertir un objet en string, il appelle la méthode toString() héritée de Object.prototype. Cette méthode retourne par défaut la chaîne [object Object], où le second terme désigne le tag interne de l’objet.

const user = { name: "Alice", age: 32 };
alert(user);
// output : [object Object]

Ce n’est pas une erreur. C’est la representation textuelle par défaut de tout objet JavaScript qui n’a pas redéfini sa propre méthode toString. Le navigateur fait exactement ce qu’on lui demande — convertir un objet en texte. Le résultat est juste inutile tel quel.

📌 À retenir : [object Object] apparaît uniquement quand un objet est converti en string implicitement. La donnée est toujours là, intacte — c’est l’affichage qui pose problème.

La mécanique derrière la coercition et Object.prototype.toString

JavaScript est un langage à typage faible. Quand on colle un objet dans un contexte qui attend une string — concaténation, template literal, alert() — le moteur déclenche une conversion automatique (coercition).

L’algorithme est le suivant :

  1. JavaScript cherche une méthode [Symbol.toPrimitive] sur l’objet
  2. Si elle n’existe pas, il appelle toString()
  3. Si toString() ne retourne pas un primitif, il tente valueOf()

Dans 99 % des cas, c’est toString() qui répond. Et comme la plupart des objets héritent directement de Object.prototype, c’est sa version par défaut qui s’exécute.

const obj = { key: "value" };
console.log(obj.toString());
// output : [object Object]

console.log(Object.prototype.toString.call(obj));
// output : [object Object]

La différence entre obj.toString() et Object.prototype.toString.call(obj) devient visible quand un objet a son propre toString :

const custom = {
  name: "Widget",
  toString() { return this.name; }
};

console.log(custom.toString());           // "Widget"
console.log(Object.prototype.toString.call(custom)); // [object Object]

Le mot-clé this joue un rôle central ici : dans custom.toString(), this pointe vers l’instance. Dans l’appel via call, la méthode du prototype s’exécute sur l’objet passé en argument, ignorant le toString personnalisé.

Les contextes où [object Object] apparaît (et ceux où il n’apparaît pas)

Pas tous les console.log sont égaux. Voici un tableau comparatif avec les outputs réels :

CodeOutputPourquoi
alert(obj)[object Object]Conversion string forcée
"Info: " + obj"Info: [object Object]"Concaténation → coercition
`User: ${obj}`"User: [object Object]"Template literal → toString()
element.textContent = obj[object Object] dans le DOMAssignation string au nœud
console.log(obj){ key: "value" } (interactif)La console inspecte l’objet, pas de conversion string
JSON.stringify(obj)'{"key":"value"}'Sérialisation structurée

Cas 1 — Concaténation. L’opérateur + avec une string à gauche force la conversion. Résultat : "prefix" + obj donne "prefix[object Object]". On s’en rend souvent compte dans des logs.

Cas 2 — Template strings. Même mécanisme que la concaténation. Écrire `Résultat : ${monObjet}` produit le même output inutile.

Cas 3 — DOM display. Assigner un objet à textContent ou innerHTML le convertit en string. C’est là que le problème se voit dans l’interface utilisateur.

Cas 4 — console.log. Contrairement aux autres, la console des navigateurs modernes (Chrome 120+, Firefox 122+) affiche une arborescence interactive. Pas de coercition string ici. C’est pour ça que console.log(obj) « fonctionne » mais alert(obj) non.

⚠️ Attention : dans Node.js, console.log utilise util.inspect(), pas toString(). Le comportement diffère des navigateurs — les objets profondément imbriqués (>2 niveaux) affichent [Object] par défaut. Ajoutez { depth: null } : console.dir(obj, { depth: null }).

Résoudre [object Object] en 4 étapes (checklist)

Inutile de chercher un fix global. La correction dépend du contexte. Voici la marche à suivre.

Étape 1 : localiser la conversion implicite. Cherchez l’endroit où l’objet finit dans une string — un +, un template literal, un alert, un textContent. Remontez la call stack si nécessaire.

Étape 2 : inspecter l’objet avec console.log ou console.dir. Vérifiez que la variable contient bien ce que vous croyez. Un console.log("data:", data) suffit souvent.

console.log("user:", user);
// output : user: { name: "Alice", age: 32 }

Étape 3 : afficher la propriété qui vous intéresse. Dans 80 % des cas, on n’a pas besoin de l’objet entier. Accédez directement à la bonne clé.

// Au lieu de :
element.textContent = user;          // [object Object]

// Faites :
element.textContent = user.name;     // "Alice"

Étape 4 : sérialiser avec JSON.stringify si besoin. Pour du debug ou un affichage complet, stringify avec indentation.

const output = JSON.stringify(user, null, 2);
console.log(output);
// {
//   "name": "Alice",
//   "age": 32
// }

Anti-patterns à éviter absolument :

  • alert(objet) pour débugger (utilisez la console)
  • "Résultat : " + objet sans accéder aux propriétés
  • document.body.innerHTML = objet (display direct dans le DOM)

Six solutions concrètes avec code et output

1. console.log / console.dir pour l’inspection

La solution la plus simple pour le debug. console.dir affiche les propriétés de manière structurée, y compris les méthodes du prototype.

const product = { name: "Écran 27p", price: 349 };
console.log(product);   // { name: "Écran 27p", price: 349 }
console.dir(product);   // idem, mais avec le prototype visible

2. JSON.stringify pour obtenir une string lisible

Trois arguments : l’objet, un replacer optionnel (function ou tableau de properties), et l’indentation.

const data = { id: 1, name: "Test", values: [10, 20, 30] };

// Version compacte
JSON.stringify(data);
// '{"id":1,"name":"Test","values":[10,20,30]}'

// Pretty print
JSON.stringify(data, null, 2);

// Sélection de propriétés
JSON.stringify(data, ["id", "name"]);
// '{"id":1,"name":"Test"}'

3. Accéder à une propriété spécifique au lieu de l’objet entier

C’est le correctif le plus fréquent dans du code de production. On n’a presque jamais besoin d’afficher un objet complet.

const config = { host: "api.example.com", port: 8080 };

// Avant (display [object Object]) :
statusBar.textContent = config;

// Après :
statusBar.textContent = `${config.host}:${config.port}`;
// output : "api.example.com:8080"

4. Redéfinir toString() sur l’objet

Utile pour des objets métier qu’on affiche régulièrement. Attention : ça modifie le comportement de toutes les conversions string.

class User {
  constructor(name, role) {
    this.name = name;
    this.role = role;
  }
  toString() {
    return `${this.name} (${this.role})`;
  }
}

const u = new User("Marc", "admin");
alert(u);  // "Marc (admin)" — plus de [object Object]

La différence avec Object.prototype.toString : la version héritée retourne toujours [object Type]. La version redéfinie retourne ce que vous voulez.

5. Function utilitaire logObject

Pour standardiser l’affichage dans un projet entier, une function wrapper évite les oublis.

function logObject(obj) {
  if (obj === null) return "null";
  if (obj === undefined) return "undefined";
  if (typeof obj !== "object") return String(obj);
  try {
    return JSON.stringify(obj, null, 2);
  } catch (e) {
    // Circular reference fallback
    return "[Objet non sérialisable]";
  }
}

console.log(logObject({ key: "value" }));
// output : '{\n  "key": "value"\n}'
console.log(logObject(null));
// output : "null"

6. Parcourir les propriétés avec for…in et hasOwnProperty

Quand on veut lister le contenu d’un objet sans les propriétés héritées du prototype :

const settings = { theme: "dark", lang: "fr", fontSize: 14 };

for (const key in settings) {
  if (settings.hasOwnProperty(key)) {
    console.log(`${key}: ${settings[key]}`);
  }
}
// output :
// theme: dark
// lang: fr
// fontSize: 14

💡 Conseil : en 2026, préférez Object.entries(obj).forEach(([k, v]) => ...) — c’est plus lisible et filtre automatiquement les propriétés héritées. Le for...in + hasOwnProperty reste pertinent quand on travaille avec des objets dont le prototype a été modifié.

Le rôle du prototype dans ce comportement

JavaScript fonctionne par chaîne de prototypes. Quand on appelle une méthode sur un objet, le moteur la cherche d’abord sur l’objet lui-même, puis remonte la chaîne jusqu’à Object.prototype (et enfin null).

monObjet → Object.prototype → null

Object.prototype.toString est la méthode « terminus ». Si aucun objet dans la chaîne ne la redéfinit, c’est elle qui s’exécute et qui retourne [object Object].

Les objets built-in redéfinissent souvent toString :

  • Array : [1, 2, 3].toString()"1,2,3"
  • Date : new Date().toString()"Sun Feb 23 2026 ..."
  • RegExp : /abc/.toString()"/abc/"

C’est pour ça que seuls les objets « plain » ({}, new Object(), objets littéraux) affichent [object Object]. Les instances de classes built-in ont leur propre implementation.

Le masquage fonctionne aussi sur des objets simples. Dès qu’on ajoute une propriété toString à un objet, la version héritée du prototype est ignorée. JavaScript ne remonte plus la chaîne — il trouve la méthode directement sur l’instance.

Cas avancés qui piègent même les développeurs expérimentés

null n’est pas un objet (malgré typeof)

Un classique. typeof null retourne "object" — un bug historique de JavaScript depuis 1995, jamais corrigé pour raison de compatibilité. Appeler null.toString() déclenche un TypeError.

typeof null;          // "object" — menteur
null.toString();      // TypeError: Cannot read properties of null
Object.prototype.toString.call(null);  // "[object Null]"

Toujours vérifier null avant d’appeler une méthode. Un simple if (obj !== null && obj !== undefined) suffit.

Objets sans prototype (nullprotoobj)

Object.create(null) crée un objet sans aucune chaîne de prototype. Résultat : pas de toString, pas de hasOwnProperty, pas de valueOf.

const nullprotoobj = Object.create(null);
nullprotoobj.key = "value";

console.log(nullprotoobj.toString);
// undefined — la méthode n'existe pas

String(nullprotoobj);
// TypeError: Cannot convert object to primitive value

Ce type d’objet est utilisé comme dictionnaire pur (Maps avant Map). On les croise dans les parsers JSON custom, certaines librairies de cache, et les internals de Node.js. Pour les afficher, JSON.stringify fonctionne. String() plante.

Un nullprotoobj se comporte différemment de tout autre objet JavaScript. Pas de méthodes héritées, pas de display par défaut, pas de conversion implicite possible.

Références circulaires : quand JSON.stringify échoue

const a = {};
const b = { ref: a };
a.ref = b;  // Référence circulaire

JSON.stringify(a);
// TypeError: Converting circular structure to JSON

Solution — un stringify « safe » avec détection de boucle :

function safeStringify(obj) {
  const seen = new WeakSet();
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) return "[Circular]";
      seen.add(value);
    }
    return value;
  }, 2);
}

console.log(safeStringify(a));
// { "ref": { "ref": "[Circular]" } }

function, Date, Array : des outputs spécifiques

Chaque type built-in a sa propre representation string :

Object.prototype.toString.call([]);           // [object Array]
Object.prototype.toString.call(new Date());   // [object Date]
Object.prototype.toString.call(function(){}); // [object Function]
Object.prototype.toString.call(42);           // [object Number]

Le tag entre crochets identifie le type interne — un particular_object. C’est d’ailleurs la technique fiable pour tester les types en JavaScript, plus sûre que typeof ou instanceof.

📊 Chiffre clé : selon le State of JS 2025, 34 % des bugs signalés par les développeurs juniors impliquent un problème de coercition de type — [object Object] en tête de liste.

Pourquoi [object Object] apparaît dans les frameworks UI

Le piège classique en React, Vue ou Angular : interpoler un objet directement dans le rendu.

React :

// ❌ Produit [object Object] dans le DOM
function Badge({ user }) {
  return <span>{user}</span>;
}

// ✅ Afficher la propriété
function Badge({ user }) {
  return <span>{user.name}</span>;
}

Vue :

<!-- ❌ -->
<p>{{ config }}</p>

<!-- ✅ -->
<p>{{ config.label }}</p>

Le mécanisme est identique au vanilla JS. Les moteurs de template convertissent les expressions en string pour les injecter dans le DOM. Un objet passe par toString(), et on retrouve notre chaîne familière.

Trois correctifs universels :

  1. Accéder à la propriété qui contient le texte voulu
  2. Stringify si on veut afficher la structure JSON (debug)
  3. Transformer en tableau de values avec Object.values(obj).join(", ") pour un affichage compact

Pour les développeurs qui travaillent avec des convertisseurs de formats ou des outils de traitement de données multimédia, ce type de bug apparaît souvent quand une API retourne un objet là où on attendait une string.

Les jobs de développement remote incluent presque toujours JavaScript dans les compétences requises — maîtriser ces mécanismes de coercition est un prérequis, pas un bonus.

Cheat sheet : cause → solution (à copier)

SymptômeCauseFix
alert affiche [object Object]Coercition stringalert(JSON.stringify(obj)) ou console.log(obj)
"text" + obj dans un logConcaténation"text" + obj.prop ou template avec propriété
DOM affiche [object Object]textContent = objtextContent = obj.prop
JSON.stringify planteRéférence circulairesafeStringify() avec WeakSet
String(obj) → TypeErrorObjet sans prototypeJSON.stringify(obj)

Snippet 1 — Pretty stringify :

const pretty = (obj) => JSON.stringify(obj, null, 2);

Snippet 2 — Safe stringify (gère les circulaires) :

function safeStringify(obj) {
  const seen = new WeakSet();
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) return "[Circular]";
      seen.add(value);
    }
    return value;
  }, 2);
}

Snippet 3 — Fonction logObject :

function logObject(obj) {
  if (obj == null) return String(obj);
  if (typeof obj !== "object") return String(obj);
  try { return JSON.stringify(obj, null, 2); }
  catch { return "[Non sérialisable]"; }
}

Bon réflexe : toujours utiliser console.log pour le debug (jamais alert), toujours accéder aux propriétés spécifiques pour l’affichage, et garder stringify pour la sérialisation complète. Le reste, c’est de la mécanique de prototype — utile à comprendre, mais rarement à manipuler directement.

Pour approfondir le sujet du développement web et des outils numériques, le guide complet des logiciels et applications couvre d’autres problématiques courantes. Côté matériel, choisir le bon PC portable pour coder en 2026 ou la bonne tablette pour le dev mobile fait aussi partie de l’équation.

FAQ

Pourquoi console.log affiche l’objet correctement mais alert affiche [object Object] ?

console.log dans les navigateurs utilise une inspection interne qui affiche l’arborescence de l’objet sans conversion string. alert, lui, appelle toString() sur l’argument pour l’afficher comme texte brut. Deux mécanismes complètement différents. Pour du debug, oubliez alertconsole.log ou console.dir font le travail sans perte d’information.

Comment afficher un objet JavaScript dans une page HTML sans obtenir [object Object] ?

Trois options selon le besoin : element.textContent = obj.name pour une propriété précise, element.textContent = JSON.stringify(obj, null, 2) pour la structure complète (debug), ou construisez le HTML dynamiquement en itérant sur Object.entries(obj). La troisième option est la plus propre pour de l’affichage utilisateur — elle permet de formater chaque propriété avec du markup.

JSON.stringify plante avec « Converting circular structure to JSON » — que faire ?

Votre objet contient des références circulaires (A pointe vers B, B pointe vers A). Utilisez un replacer custom avec un WeakSet pour détecter les boucles : à chaque objet rencontré, vérifiez s’il est déjà dans le Set. Si oui, remplacez par "[Circular]". Le snippet safeStringify présenté dans cet article gère ce cas. Les librairies comme flatted (2 Ko) ou json-stringify-safe offrent une solution prête à l’emploi.

L'auteur

L'auteur

Redacteur passionné. Il partage ses connaissances à travers des guides pratiques et des outils gratuits.

Cet article est publie a titre informatif. Faites vos propres recherches avant toute decision.