Aller au contenu principal
18 min de lecture

Comprendre et corriger « [object Object] » en JavaScript : causes, output selon le contexte et solutions

Pourquoi JavaScript affiche [object Object] ? Découvrez les causes, le rôle de toString et prototype, et les solutions concrètes pour afficher vos objets correctement.

18 min de lecture
Partager
Comprendre et corriger « [object Object] » en JavaScript : causes, output selon le contexte et solutions

Que signifie « [object Object] » et pourquoi ça apparaît partout

[object Object] — ce message cryptique qui surgit dans la console, dans un alert, ou pire, directement dans le DOM de votre page. Ce n’est pas un bug. C’est la représentation string par défaut que JavaScript retourne quand on force un objet à devenir du texte.

Concrètement :

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

Le moteur appelle Object.prototype.toString() sur l’objet. Cette méthode retourne la chaîne "[object Object]" — le premier « object » désigne le type général, le second est le tag interne. Les propriétés (name, age, chaque key et chaque value) sont complètement ignorées.

💡 Conseil : Taper console.log(typeof monObjet) avant tout — si le retour est "string", votre objet a déjà été converti et les propriétés sont perdues.

Bon, c’est la théorie. Le problème, c’est que 90 % des devs tombent dessus sans comprendre quel mécanisme déclenche cette conversion. Et les objets en JavaScript sont partout : retour d’API, state React, objets du DOM.

Comparatif des contextes d’affichage : alert vs console vs concaténation

Tous les contextes ne traitent pas un objet de la même manière. Voici ce qui se passe réellement selon l’endroit où vous tentez d’afficher vos objets.

alert(objet) : conversion implicite en string

alert() attend une string. Point. Si on lui passe un objet, JavaScript appelle toString() dessus. Le prototype de Object retourne "[object Object]".

const config = { theme: "dark", lang: "fr" };
alert(config);
// Output : [object Object]

Pas de propriétés visibles, pas de key, pas de value. Juste la représentation brute.

console.log(objet) : inspection vs stringification

Le comportement de console.log est radicalement différent. La console du navigateur affiche un objet interactif — on peut déplier les propriétés, voir chaque key et value, remonter la chaîne de prototype.

const config = { theme: "dark", lang: "fr" };
console.log(config);
// Output : {theme: "dark", lang: "fr"} (interactif)

Aucune conversion toString ici. Le moteur passe l’objet tel quel au devtools.

Concaténation string et template literals

Dès qu’un objet se retrouve dans une concaténation, JavaScript force la coercition :

const obj = { id: 42 };
const msg = "Résultat : " + obj;
console.log(msg);
// Output : "Résultat : [object Object]"

const tpl = `Valeur = ${obj}`;
console.log(tpl);
// Output : "Valeur = [object Object]"

Même mécanisme. Le moteur appelle toString() sur l’objet avant de le fusionner avec la string.

Affichage UI/HTML : le piège classique

document.getElementById("result").textContent = monObjet;
// Display : [object Object]

Le DOM attend du texte. L’objet est converti via toString(). On voit [object Object] directement dans la page.

⚠️ Attention : Les frameworks comme React convertissent aussi les objets passés comme enfants JSX — l’erreur « Objects are not valid as a React child » vient du même mécanisme.

Tableau récapitulatif

ContexteConversion toString ?Output typiquePropriétés visibles ?
alert(objet)Oui[object Object]Non
console.log(objet)NonObjet interactifOui (cliquable)
"" + objetOui[object Object]Non
Template literalOui[object Object]Non
DOM textContentOui[object Object]Non
JSON.stringify(objet)Non (sérialisation){"key":"value"}Oui (string JSON)

📌 À retenir : Seul console.log (et console.dir) préserve la structure de l’objet. Tout le reste déclenche toString() via le prototype.

Le mécanisme de coercition : pourquoi toString retourne « [object Object] »

Quand JavaScript a besoin d’une string et reçoit un objet, il suit un chemin précis.

D’abord, le moteur cherche Symbol.toPrimitive sur l’objet. S’il n’existe pas (cas courant), il appelle toString(). Cette méthode est héritée via la chaîne de prototype — concrètement, c’est Object.prototype.toString qui s’exécute.

const obj = { x: 1 };
obj.toString();
// retourne "[object Object]"

Object.prototype.toString.call(obj);
// retourne "[object Object]"

Le format retourné suit le pattern [object Tag]. Le tag par défaut est "Object". D’où [object Object].

Pour un Array, le prototype a sa propre implémentation de toString :

[1, 2, 3].toString();
// retourne "1,2,3"

Object.prototype.toString.call([1, 2, 3]);
// retourne "[object Array]"

Deux versions de toString, deux résultats. Le prototype de l’objet détermine quelle méthode est appelée — c’est la base de l’héritage en JavaScript.

Conversion implicite vs appel explicite

Appeler objet.toString() directement ou laisser JavaScript le faire implicitement (via alert, concaténation string) produit le même résultat. La différence : quand c’est implicite, on ne s’y attend pas, et l’output [object Object] surprend.

const data = { code: 200, status: "ok" };

// Explicite — on sait ce qu'on fait
console.log(data.toString());
// Output : [object Object]

// Implicite — piège
console.log("Réponse : " + data);
// Output : Réponse : [object Object]

📊 Chiffre clé : Sur StackOverflow, la question « What does [object Object] mean in JavaScript » cumule plus de 800 000 vues — c’est l’un des pièges les plus fréquents du langage.

La chaîne de prototype : pourquoi Object.prototype compte

Chaque objet en JavaScript hérite de propriétés et de méthodes via sa chaîne de prototype. Quand on crée un objet littéral {}, son prototype pointe vers Object.prototype. C’est là que vivent toString, hasOwnProperty, valueOf et les autres méthodes de base.

Héritage : méthodes du prototype vs propriétés propres

const voiture = { marque: "Peugeot", km: 45000 };

// Propriétés propres (sur l'instance)
voiture.hasOwnProperty("marque");  // true
voiture.hasOwnProperty("km");     // true

// Méthode héritée du prototype
voiture.hasOwnProperty("toString"); // false
voiture.toString();                 // fonctionne quand même → prototype

La méthode toString n’est pas une propriété de voiture. Elle vient du prototype. Le moteur remonte la chaîne jusqu’à la trouver sur Object.prototype.

Function constructeur, new et this

Avec un constructeur function, le prototype joue un rôle direct :

function Produit(name, price) {
  this.name = name;
  this.price = price;
}

Produit.prototype.display = function() {
  return `${this.name} — ${this.price} €`;
};

Produit.prototype.toString = function() {
  return this.display();
};

const p = new Produit("SSD Samsung 990 Pro", 89);
console.log(p.toString());
// Output : "SSD Samsung 990 Pro — 89 €"

alert(p);
// Output : "SSD Samsung 990 Pro — 89 €" (toString custom)

Ici, new crée une instance dont le prototype pointe vers Produit.prototype. Le this à l’intérieur du constructeur réfère à la nouvelle instance. La méthode toString sur le prototype retourne une string lisible au lieu de [object Object].

hasOwnProperty : distinguer hérité et propre

const obj = { key: "value", id: 1 };

for (const prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    console.log(prop, obj[prop]);
  }
}
// Output :
// key value
// id 1

La boucle for...in itère aussi sur les propriétés héritées du prototype. Le guard hasOwnProperty filtre uniquement les propriétés propres de l’instance. Sur des objets complexes avec des prototypes étendus, c’est indispensable.

Résoudre « [object Object] » : checklist de diagnostic

Quand [object Object] apparaît là où on attendait des données lisibles, voici comment réagir.

Tableau diagnostic

SymptômeCause probableFix
alert affiche [object Object]Objet passé directementalert(JSON.stringify(obj))
DOM affiche [object Object]Objet assigné à textContentExtraire la propriété : el.textContent = obj.name
Log montre [object Object] dans une stringConcaténation string + objetUtiliser console.log(obj) séparément
API retourne [object Object]Double parsing ou objet non sérialiséVérifier JSON.parse() / JSON.stringify()
React affiche l’erreur « Objects not valid »Objet passé comme enfant JSXExtraire une value ou stringify

Étape 1 : inspecter avec console

console.log(monObjet);        // Objet interactif
console.dir(monObjet);        // Arbre complet avec prototype
console.table(monObjet);      // Display en tableau (propriétés en colonnes)

console.table est sous-utilisé. Pour un objet avec des propriétés nommées, le display sous forme de tableau rend les key/value immédiatement lisibles.

Étape 2 : accéder aux propriétés au lieu d’afficher l’objet brut

// Mauvais
document.title = response;
// → [object Object]

// Bon
document.title = response.title;
// → "Mon titre"

Neuf fois sur dix, le fix consiste à extraire la propriété (key) dont on a besoin au lieu de passer l’objet entier.

Étape 3 : stringify pour un output lisible

const data = { name: "GPU RTX 5090", price: 1999, stock: true };
console.log(JSON.stringify(data, null, 2));
// Output :
// {
//   "name": "GPU RTX 5090",
//   "price": 1999,
//   "stock": true
// }

Le troisième argument (2) ajoute l’indentation. Le second (null) est le replacer — on peut l’utiliser pour filtrer des propriétés.

💡 Conseil : Raccourci Chrome DevTools — taper copy(JSON.stringify(obj, null, 2)) dans la console copie l’objet formaté directement dans le presse-papiers.

Solutions pratiques avec exemples de code

console.log vs console.table

Pour un array d’objets (retour d’API typique) :

const users = [
  { name: "Alice", role: "dev" },
  { name: "Bob", role: "ops" }
];

console.table(users);
// Display en grille : index | name | role

Le display tabulaire transforme un array d’objets en quelque chose de lisible instantanément. Bien plus efficace que console.log pour déboguer des listes.

Afficher une propriété précise

const device = { name: "iPhone 17 Pro", price: 1299 };

// Destructuring
const { name, price } = device;
console.log(`${name} : ${price} €`);
// Output : "iPhone 17 Pro : 1299 €"

Le destructuring extrait chaque value par key. Pas de conversion toString, pas de [object Object].

JSON.stringify : formatage et contrôle

const config = {
  name: "wattlet",
  key: "abc123",
  nested: { value: 42 }
};

// Stringify complet
JSON.stringify(config);
// '{"name":"wattlet","key":"abc123","nested":{"value":42}}'

// Avec filtre (replacer)
JSON.stringify(config, ["name", "nested"], 2);
// Seules les propriétés "name" et "nested" apparaissent

Attention : stringify retourne undefined (pas une string) pour les fonctions, Symbol, et les values undefined. Ces propriétés disparaissent silencieusement de l’output.

toString personnalisé sur le prototype

class Smartphone {
  constructor(name, price) {
    this.name = name;
    this.price = price;
  }

  toString() {
    return `${this.name} (${this.price} €)`;
  }
}

const phone = new Smartphone("Xiaomi 17 Pro Max", 599);
alert(phone);
// Output : "Xiaomi 17 Pro Max (599 €)"

console.log("Achat : " + phone);
// Output : "Achat : Xiaomi 17 Pro Max (599 €)"

Définir toString sur le prototype (ou dans une class, ce qui revient au même) retourne une string contrôlée. L’objet ne produit plus [object Object] lors de la coercition. D’ailleurs, si vous cherchez un bon smartphone photo en 2026, les tests montrent que le capteur compte moins que le traitement logiciel.

Cas limites et pièges : null, circular, nullprotoobj

null : le faux objet

typeof null;
// retourne "object" — un bug historique de JavaScript depuis 1995

const val = null;
val.toString();
// TypeError: Cannot read properties of null

null a le type "object" mais n’est PAS un objet. Appeler toString ou accéder à une propriété sur null déclenche un TypeError. Toujours vérifier avant :

if (val !== null && typeof val === "object") {
  console.log(JSON.stringify(val));
}

Ce guard bloque null, undefined et les primitives. Sans lui, le code casse sur null — et dans une codebase réelle, null arrive plus souvent qu’on ne le croit (retour d’API vide, state non initialisé, propriétés optionnelles).

stringify et références circulaires

const a = {};
const b = { ref: a };
a.ref = b;

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

Deux objets qui se réfèrent mutuellement créent une boucle. stringify ne sait pas la gérer et lève une exception. Pas de fallback, pas de null — juste un crash.

Objets à prototype null : nullprotoobj

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

nullprotoobj.toString();
// TypeError: nullprotoobj.toString is not a function

nullprotoobj.hasOwnProperty("key");
// TypeError: nullprotoobj.hasOwnProperty is not a function

Un objet créé avec Object.create(null) — un nullprotoobj — n’a PAS de prototype. Aucune méthode héritée : pas de toString, pas de hasOwnProperty, pas de valueOf. C’est un objet « nu » avec uniquement ses propriétés propres.

On utilise un nullprotoobj comme dictionnaire pur (pas de collision avec les noms de méthodes du prototype). Redis, certains parsers JSON, et des libs comme mime-types s’en servent.

Le fix pour travailler avec un nullprotoobj :

const nullprotoobj = Object.create(null);
nullprotoobj.name = "test";

// hasOwnProperty via call
Object.prototype.hasOwnProperty.call(nullprotoobj, "name"); // true

// toString via call
Object.prototype.toString.call(nullprotoobj);
// retourne "[object Object]"

// Stringify fonctionne normalement
JSON.stringify(nullprotoobj);
// '{"name":"test"}'

Avec Object.prototype.hasOwnProperty.call(), on emprunte la méthode au prototype de Object et on l’applique au nullprotoobj. Même logique pour toString.

⚠️ Attention : Un nullprotoobj n’apparaît pas souvent dans du code applicatif, mais les bundlers et les runtimes Node.js en créent régulièrement. Si obj.hasOwnProperty lève une erreur, c’est probablement un nullprotoobj.

Quand on travaille avec du matériel informatique, ces subtilités de prototype comptent moins que la fiabilité du code — mais sur un projet de tablette Android à bon rapport qualité-prix, un objet mal sérialisé peut casser tout le rendu d’une fiche produit.

Protection complète contre null et nullprotoobj

function safeDisplay(obj) {
  if (obj === null) return "null";
  if (obj === undefined) return "undefined";
  if (typeof obj !== "object") return String(obj);
  // Guard pour nullprotoobj
  if (!Object.getPrototypeOf(obj)) {
    return JSON.stringify(obj);
  }
  return obj.toString();
}

Ce code gère null, undefined, les primitives, et les nullprotoobj. Chaque cas retourne une string lisible au lieu de crasher.

Object.prototype.toString, Symbol.toStringTag et les objets particuliers

Pourquoi certains objets ne retournent pas « [object Object] »

Object.prototype.toString.call([]);
// "[object Array]"

Object.prototype.toString.call(new Date());
// "[object Date]"

Object.prototype.toString.call(/regex/);
// "[object RegExp]"

Object.prototype.toString.call(null);
// "[object Null]"

Object.prototype.toString.call(undefined);
// "[object Undefined]"

Chaque type natif a un tag interne. La representation retournée par Object.prototype.toString reflète ce tag — c’est le moyen le plus fiable de vérifier le type réel d’une value en JavaScript.

Symbol.toStringTag : personnaliser la representation

class Monitor {
  get [Symbol.toStringTag]() {
    return "Monitor";
  }
}

const screen = new Monitor();
Object.prototype.toString.call(screen);
// "[object Monitor]"

En définissant Symbol.toStringTag sur le prototype, on contrôle le tag retourné. C’est ce que font Map ([object Map]), Set ([object Set]), et les générateurs.

Un objet particulier (particular_object) — une instance avec un tag personnalisé — se distingue des objets génériques. Le name retourné dans la representation [object X] identifie sa nature sans ambiguïté.

class GPUBenchmark {
  constructor(name, score) {
    this.name = name;
    this.score = score;
  }
  get [Symbol.toStringTag]() {
    return "GPUBenchmark";
  }
  toString() {
    return `${this.name}: ${this.score} pts`;
  }
}

const bench = new GPUBenchmark("RTX 5090", 48500);
Object.prototype.toString.call(bench);
// "[object GPUBenchmark]" — particular_object identifié

String(bench);
// "RTX 5090: 48500 pts" — toString custom

Pour les amateurs de montres connectées, le même principe s’applique : chaque instance d’un objet « particulier » retourne une representation qui le distingue — nom du modèle, capteurs disponibles, version firmware.

Mini-utility : safeStringify pour un output fiable

Les références circulaires cassent JSON.stringify. Voici une function utilitaire qui gère le cas :

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

Using safeStringify en pratique

const a = { name: "nodeA" };
const b = { name: "nodeB", ref: a };
a.ref = b;

console.log(safeStringify(a));
// Output :
// {
//   "name": "nodeA",
//   "ref": {
//     "name": "nodeB",
//     "ref": "[Circular]"
//   }
// }

La function utilise un WeakSet pour tracker les objets déjà vus. Quand une référence circulaire apparaît, elle retourne "[Circular]" au lieu de crasher. Le WeakSet (pas un Set classique) évite les fuites mémoire — les objets restent éligibles au garbage collection.

Limites : les values de type function disparaissent (stringify les ignore), BigInt lève une erreur (pas de sérialisation native), et les propriétés avec value undefined sont omises. Pour un log de debug, c’est suffisant. Pour de la sérialisation métier, il faut un replacer plus sophistiqué.

// Using dans un logger
function debugLog(label, obj) {
  console.log(`[DEBUG] ${label}:`, safeStringify(obj));
}

debugLog("config", { key: "api_key", value: "xxx", nested: { id: null } });
// Output : [DEBUG] config: {"key":"api_key","value":"xxx","nested":{"id":null}}

Le null dans nested.id est correctement sérialisé — contrairement à undefined qui disparaîtrait.

Pour les développeurs qui bossent avec des polices d’écriture côté interface, un display cassé par [object Object] dans le DOM est un bug courant. Ce genre d’utilitaire évite la plupart des cas.

FAQ : réponses concrètes sur « [object Object] »

What does « [object Object] » mean in JavaScript ?

C’est la string retournée par Object.prototype.toString() quand JavaScript convertit un objet en texte. Le premier « object » indique le type, le second est le tag interne. Ce n’est pas une erreur — c’est le comportement par défaut pour tout objet sans toString personnalisé sur son prototype.

Comment afficher les propriétés d’un objet au lieu de « [object Object] » ?

Trois options selon le contexte : JSON.stringify(obj) pour une string lisible, console.table(obj) pour un display en tableau dans les DevTools, ou accéder directement à une propriété (obj.name, obj.key). Pour un objet avec des propriétés imbriquées, JSON.stringify(obj, null, 2) avec indentation reste la méthode la plus fiable.

Pourquoi alert(objet) et console.log(objet) donnent des résultats différents ?

alert() force une conversion en string via toString — d’où [object Object]. console.log() passe l’objet tel quel au moteur de rendu des DevTools, qui affiche un arbre interactif avec toutes les propriétés et le prototype. Résultat : même objet, deux outputs totalement différents. Pour déboguer, préférer toujours console.log ou console.dir à alert.

Explorer aussi

Dans cette catégorie

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.