Aller au contenu principal
14 min de lecture

Comprendre et corriger « [object Object] » en JavaScript : toString, stringify et console

Pourquoi JavaScript affiche [object Object] au lieu de vos données ? Diagnostic, 5 correctifs immédiats et bonnes pratiques toString, stringify, console.

14 min de lecture
Partager
Comprendre et corriger « [object Object] » en JavaScript : toString, stringify et console

Copiez un objet JavaScript dans un alert(), et le navigateur vous crache [object Object]. Pas d’erreur rouge dans la console, pas de crash — juste cette chaîne cryptique qui remplace vos données. Le réflexe : penser à un bug. La réalité : c’est le comportement par défaut du langage quand il convertit un objet en string.

Ce message apparaît des milliers de fois par jour sur Stack Overflow. Pourtant, la plupart des guides en ligne se contentent de balancer JSON.stringify() comme remède universel sans expliquer pourquoi ça arrive ni quand cette solution ne suffit pas. On va couvrir les deux.

Que signifie [object Object] et pourquoi le résultat n’est pas un bug

La coercition en chaîne : le mécanisme derrière le rideau

Quand JavaScript doit transformer un objet en string — pour un alert(), une concaténation avec +, ou un template literal — il appelle la méthode toString(). Cette méthode vit sur Object.prototype, le prototype racine dont héritent tous les objets. Et la version par défaut retourne toujours la même chose : [object Object].

Le premier mot entre crochets désigne le type interne (toujours « object » pour les objets classiques). Le second correspond au tag de l’objet, tiré de Symbol.toStringTag ou de la classification interne. Pour un objet littéral {}, le tag est « Object ». D’où [object Object].

const user = { name: "Alice", age: 32 };
Object.prototype.toString.call(user);
// retourne "[object Object]"

Aucun prototype personnalisé, aucun toString() redéfini sur cet objet → le moteur remonte la chaîne de prototypes jusqu’à Object.prototype.toString et retourne la représentation générique. C’est un comportement voulu, pas une anomalie.

alert vs console.log : deux façons de lire un objet

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

alert() convertit son argument en string avant de l’afficher. console.log(), lui, inspecte l’objet sans le convertir — c’est pour ça qu’on voit les propriétés. La confusion vient de là : deux fonctions, deux traitements de l’objet, deux résultats.

💡 Conseil : Remplacez systématiquement alert() par console.log() ou console.dir() pour le debug. alert() bloque le thread principal et détruit l’information en convertissant l’objet en string.

Cinq correctifs immédiats pour afficher un objet sans [object Object]

Inspecter avec console.log et console.dir

console.log() affiche l’objet de façon interactive dans le navigateur. On peut déplier les propriétés, naviguer dans les objets imbriqués. console.dir() force un affichage en arbre même quand log affiche du HTML (cas des éléments DOM).

const product = { name: "MacBook Pro M4", price: 2399, stock: true };
console.log(product);
// output : { name: "MacBook Pro M4", price: 2399, stock: true }
console.dir(product);
// output identique, mais garantit le format objet

Convertir en JSON avec JSON.stringify

JSON.stringify() retourne une chaîne JSON lisible. Avec les paramètres d’indentation, l’output devient facile à lire :

const order = { id: 4821, items: ["clavier", "souris"], total: 127.50 };
const json = JSON.stringify(order, null, 2);
console.log(json);
// output :
// {
//   "id": 4821,
//   "items": ["clavier", "souris"],
//   "total": 127.5
// }

Le deuxième argument (null ici) est un replacer — on y reviendra pour filtrer des propriétés sensibles. Le troisième fixe l’indentation. Pour un affichage compact, on l’omet.

Accéder à une propriété précise par sa key

Parfois, on n’a besoin que d’une seule value. Inutile de sérialiser l’objet entier :

const user = { name: "Marc", role: "admin" };
alert(user.name);  // output : "Marc" — pas de [object Object]

L’accès par key (object.name ou object["name"]) retourne directement la value, qui est déjà une string ou un nombre. Pas de conversion, pas de surprise.

console.table pour les objets tabulaires

const servers = [
  { name: "prod-1", cpu: "72%", ram: "8.3 GB" },
  { name: "prod-2", cpu: "45%", ram: "6.1 GB" }
];
console.table(servers);

console.table() retourne un tableau formaté directement dans la console. Chaque key devient un en-tête de colonne, chaque objet une ligne. Pour des objets avec 3 à 8 propriétés, c’est le format le plus lisible.

Checklist : quel outil selon le contexte

BesoinMéthodeRetourne
Debug rapideconsole.log(objet)Objet interactif
Copier-coller de donnéesJSON.stringify(objet, null, 2)String JSON formatée
Afficher dans le DOMelement.textContent = objet.namePropriété ciblée
Tableau de donnéesconsole.table(objets)Tableau formaté
Envoyer à une APIJSON.stringify(objet)String JSON compacte

⚠️ Attention : JSON.stringify() ignore silencieusement les propriétés de type function, Symbol et undefined. Si votre objet contient des méthodes, elles disparaîtront de l’output sans avertissement.

Diagnostic par contexte : pourquoi [object Object] apparaît et comment corriger

alert(objet) → coercition string automatique

const data = { status: "ok", code: 200 };
alert(data);  // "[object Object]"
// Fix :
alert(JSON.stringify(data));  // '{"status":"ok","code":200}'

alert() appelle toString() via le prototype de l’objet. La méthode retourne la représentation par défaut. Le correctif : passer par stringify ou accéder à la propriété voulue.

Concaténation string + objet

const user = { name: "Léa" };
const msg = "Bonjour " + user;
// msg = "Bonjour [object Object]"
// Fix :
const msg2 = "Bonjour " + user.name;
// msg2 = "Bonjour Léa"

L’opérateur + avec une string à gauche déclenche la coercition. JavaScript appelle toString() sur l’objet à droite. Le prototype retourne [object Object]. Le correctif : cibler la key précise, ou utiliser stringify.

Template literal : même piège, autre syntaxe

const item = { label: "USB-C", price: 12 };
console.log(`Article : ${item}`);
// output : "Article : [object Object]"
// Fix :
console.log(`Article : ${item.label} — ${item.price} €`);
// output : "Article : USB-C — 12 €"

Les template literals appellent aussi toString() sur les objets interpolés. Même mécanisme de prototype, même résultat.

Injection dans le DOM via innerHTML ou textContent

const config = { mode: "sombre", lang: "fr" };
document.getElementById("info").textContent = config;
// display : "[object Object]"
// Fix :
document.getElementById("info").textContent = JSON.stringify(config);
// display : '{"mode":"sombre","lang":"fr"}'

Pour un display propre dans l’interface, on préfère accéder aux propriétés individuelles de l’objet et construire le HTML manuellement plutôt que de dump tout l’objet.

📌 À retenir : Chaque fois qu’un objet est converti implicitement en string — par +, template literal, alert(), ou affectation au DOM — JavaScript passe par toString() sur le prototype. Identifier le point de coercition permet de choisir le bon correctif.

Le mécanisme interne : Object.prototype.toString, prototype et this

La chaîne de prototypes : où JavaScript trouve toString()

Chaque objet en JavaScript possède un prototype. Ce prototype est lui-même un objet, avec son propre prototype. Cette chaîne remonte jusqu’à Object.prototype, qui est le prototype terminal — son prototype à lui est null.

const car = { brand: "Peugeot", year: 2025 };
// car → Object.prototype → null
car.toString();
// retourne "[object Object]"
// car n'a pas de toString() propre
// → remonte au prototype → Object.prototype.toString()

Quand on appelle toString() sur car, le moteur cherche la méthode sur l’objet lui-même. Absent. Il remonte au prototype (Object.prototype), trouve toString(), et l’exécute. Le prototype fournit la méthode, l’objet fournit le contexte (this).

this : le contexte d’exécution qui change tout

Object.prototype.toString utilise this pour déterminer quel objet il décrit. Quand on appelle car.toString(), this pointe vers car. Le prototype exécute la méthode, mais this cible l’objet appelant.

const date = new Date();
Object.prototype.toString.call(date);
// retourne "[object Date]"

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

const regex = /test/;
Object.prototype.toString.call(regex);
// retourne "[object RegExp]"

Object.prototype.toString.call(value) est une technique classique pour identifier le type réel d’une value. this est forcé via call(), et la méthode retourne le tag interne de l’objet. Les prototypes d’Array, Date et RegExp redéfinissent toString(), mais en passant par Object.prototype directement, on obtient le type brut.

Pourquoi le résultat est générique pour les objets littéraux

Un objet créé avec {} ou new Object() n’a pas de Symbol.toStringTag. Son prototype est directement Object.prototype. La méthode toString() retourne donc [object Object] — le tag par défaut. Les objets natifs (Date, Map, Set, Error) ont chacun un tag spécifique sur leur prototype, ce qui donne des résultats comme [object Date] ou [object Map].

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

const map = new Map();
map.toString();
// retourne "[object Map]" grâce à Symbol.toStringTag

Pour vos propres objets, ajouter Symbol.toStringTag change le tag :

const myObj = { [Symbol.toStringTag]: "Config" };
Object.prototype.toString.call(myObj);
// retourne "[object Config]"

Bon, concrètement, dans la plupart des cas, on ne touche pas à toStringTag. L’approche stringify ou console.log couvre 95 % des besoins. Cette astuce est surtout utile pour les auteurs de bibliothèques qui veulent un display propre dans les outils de debug.

Si vous travaillez avec d’autres logiciels et outils de développement, comprendre le fonctionnement des prototypes aide aussi à déboguer d’autres situations liées aux objets.

toString vs JSON.stringify vs console : comparatif structuré

toString() : simple mais limité

toString() retourne une string basique. Sur un objet sans méthode custom, elle retourne [object Object]. Sur un objet avec un toString() redéfini, elle retourne ce qu’on a codé.

const point = {
  x: 10,
  y: 25,
  toString() { return `Point(${this.x}, ${this.y})`; }
};
point.toString();        // retourne "Point(10, 25)"
String(point);           // retourne "Point(10, 25)"
alert(point);            // output : "Point(10, 25)"

Le prototype de point a maintenant sa propre méthode toString() — JavaScript ne remonte plus jusqu’à Object.prototype. L’objet contrôle sa représentation en string.

Limite : toString() ne gère pas les objets imbriqués. Pour un objet complexe avec des propriétés profondes, il faut coder manuellement la représentation.

JSON.stringify() : le couteau suisse

stringify convertit un objet en string JSON. Il parcourt récursivement toutes les propriétés et retourne une représentation complète :

const user = {
  name: "Sophie",
  address: { city: "Lyon", zip: "69001" },
  tags: ["dev", "js"]
};
JSON.stringify(user, null, 2);
// retourne une string JSON indentée avec toutes les propriétés

Avantages : gère les objets imbriqués, les tableaux, les valeurs null. Utilisable pour le stockage (localStorage), le transport (API fetch), et le debug.

Limites importantes :

  • Les propriétés de type function sont ignorées — stringify les supprime silencieusement
  • Les valeurs undefined sont supprimées des objets (conservées comme null dans les tableaux)
  • Les références circulaires lèvent une erreur TypeError
  • Les objets Date sont convertis en string ISO, pas en objet Date au JSON.parse()

console.log / console.dir / console.table

console.log() affiche un objet interactif dans les DevTools. On déplie les propriétés, on navigue dans les prototypes imbriqués. console.dir() fait la même chose mais force le format objet (utile pour les nœuds DOM). console.table() affiche un tableau pour les arrays d’objets.

Le gros avantage : aucune conversion. L’objet reste un objet. On voit les function, les Symbol, les valeurs undefined, les prototypes — tout ce que stringify masque.

Tableau comparatif

CritèretoString()JSON.stringify()console.log()
Objets imbriquésNon (sauf code custom)Oui (récursif)Oui (interactif)
Fonctions visiblesDépend du codeNon (ignorées)Oui
Références circulairesN/AErreur TypeErrorOui (avec indicateur)
Propriétés nullDépend du codeOui (affiche null)Oui
Usage debugLimitéBon (copier-coller)Meilleur
Usage UI/transportOui (si custom)OuiNon
Objets sans prototypeFonctionne via call()OuiOui

Si vous développez des outils de conversion ou des scripts d’analyse, maîtriser ces trois méthodes évite des heures de debug sur des propriétés fantômes.

Cas limites : null, objets sans prototype et références circulaires

null : l’objet qui n’en est pas un

typeof null retourne "object" — un bug historique de JavaScript qui date de 1995 et qui ne sera jamais corrigé (trop de code en dépend). Mais null n’est pas un objet. Il n’a pas de prototype, pas de propriétés, pas de méthodes.

const data = null;
data.toString();    // TypeError: Cannot read properties of null
data.name;          // TypeError: Cannot read properties of null
JSON.stringify(data); // retourne "null" (string)
console.log(data);    // output : null

Accéder à n’importe quelle propriété de null lève une erreur. Le seul moyen sûr de le display : vérifier d’abord que la value n’est pas null.

function safeDisplay(obj) {
  if (obj === null) return "null";
  if (obj === undefined) return "undefined";
  return JSON.stringify(obj, null, 2);
}

Null est la source numéro un des TypeError en production. Avant d’accéder aux propriétés d’un objet retourné par une API ou une base de données, testez toujours la value. Un objet null n’a ni prototype ni propriétés — c’est le néant.

Object.create(null) : l’objet sans prototype

Un objet créé avec Object.create(null) n’a aucun prototype. Pas de Object.prototype dans la chaîne. Pas de toString(). Pas de hasOwnProperty(). Rien.

const nullprotoobj = Object.create(null);
nullprotoobj.name = "cache";
nullprotoobj.ttl = 3600;

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

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

Ce type d’objet (parfois appelé « nullprotoobj » ou « dictionary object ») est utilisé dans les moteurs de cache, les parsers, et les objets de configuration sécurisés. L’absence de prototype évite les collisions avec les propriétés héritées — un nullprotoobj avec une key "toString" ne masque pas une méthode du prototype puisqu’il n’y en a pas.

Le problème : impossible d’appeler toString() ou hasOwnProperty() directement sur un nullprotoobj. Les correctifs :

// Sérialiser un nullprotoobj
JSON.stringify(nullprotoobj);
// retourne '{"name":"cache","ttl":3600}' — stringify fonctionne

// Vérifier une propriété sur un nullprotoobj
Object.prototype.hasOwnProperty.call(nullprotoobj, "name");
// retourne true

// Alternative moderne pour vérifier une key
Object.hasOwn(nullprotoobj, "name");
// retourne true (ES2022)

JSON.stringify ne dépend pas du prototype de l’objet — il parcourt les propriétés énumérables directement. C’est le moyen le plus fiable de sérialiser un nullprotoobj.

Pour itérer sur les propriétés d’un nullprotoobj :

const nullprotoobj2 = Object.create(null);
nullprotoobj2.host = "localhost";
nullprotoobj2.port = 5432;
nullprotoobj2.db = "app_prod";

// for...in fonctionne même sans prototype
for (const key in nullprotoobj2) {
  console.log(`${key}: ${nullprotoobj2[key]}`);
}
// output :
// host: localhost
// port: 5432
// db: app_prod

// Object.keys fonctionne aussi sur un nullprotoobj
Object.keys(nullprotoobj2);
// retourne ["host", "port", "db"]

📊 Chiffre clé : Dans le code source de Node.js, plus de 200 occurrences de Object.create(null) sont utilisées pour créer des objets sans prototype — principalement dans les parsers HTTP, le système de modules et les caches internes.

Références circulaires : quand stringify plante

Un objet qui se référence lui-même — ou deux objets qui se référencent mutuellement — crée une référence circulaire. JSON.stringify ne sait pas gérer ça et lève une erreur :

const objA = { name: "A" };
const objB = { name: "B", ref: objA };
objA.ref = objB;

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

Le correctif : un stringify sécurisé qui détecte les références circulaires :

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);
}

safeStringify(objA);
// retourne :
// {
//   "name": "A",
//   "ref": {
//     "name": "B",
//     "ref": "[Circular]"
//   }
// }

Le WeakSet stocke chaque objet déjà visité. Quand stringify retombe sur un objet connu, le replacer retourne "[Circular]" au lieu de boucler. Les propriétés null et les valeurs primitives (string, number) ne posent pas de problème — seuls les objets référencés créent des boucles.

console.log() gère les circulaires nativement : les DevTools affichent un indicateur [Circular] ou un lien cliquable. Pour du code serveur (Node.js), util.inspect() fait la même chose.

Bonnes pratiques : toString custom et logging en production

Écrire un toString() utile sur vos objets

La méthode toString() par défaut du prototype retourne [object Object]. Redéfinir cette méthode sur vos objets (ou classes) change le comportement de alert(), de la concaténation, et du template literal :

class User {
  constructor(name, role) {
    this.name = name;
    this.role = role;
    this._token = "sk-abc123"; // propriété sensible
  }
  toString() {
    return `User(${this.name}, ${this.role})`;
  }
}

const admin = new User("Claire", "admin");
console.log(`Connecté : ${admin}`);
// output : "Connecté : User(Claire, admin)"
// → pas de [object Object], et _token n'est pas exposé

La méthode toString() sur la classe remplace celle du prototype Object.prototype. JavaScript ne remonte plus la chaîne — il trouve la méthode directement sur le prototype de User. Le résultat : un display contrôlé qui n’expose pas les propriétés sensibles.

Masquer des properties avant le display

En production, JSON.stringify peut exposer des tokens, mots de passe ou données personnelles si on n’est pas vigilant. Le replacer permet de filtrer :

function safelog(obj, sensitiveKeys = ["password", "token", "_token", "secret"]) {
  return JSON.stringify(obj, function(key, value) {
    if (sensitiveKeys.includes(key)) return "[REDACTED]";
    if (typeof value === "object" && value !== null) {
      // Gérer les nullprotoobj qui n'ont pas hasOwnProperty
      return value;
    }
    return value;
  }, 2);
}

const config = { host: "api.example.com", token: "sk-live-xyz", port: 443 };
console.log(safelog(config));
// output :
// {
//   "host": "api.example.com",
//   "token": "[REDACTED]",
//   "port": 443
// }

Logger pour dev et prod : deux comportements

const logger = {
  log(label, obj) {
    if (process.env.NODE_ENV === "production") {
      // En prod : JSON compact, propriétés filtrées
      const clean = JSON.stringify(obj, (key, value) => {
        if (key.startsWith("_")) return undefined;
        return value;
      });
      process.stdout.write(`[${label}] ${clean}\n`);
    } else {
      // En dev : objet complet, inspecté par console
      console.log(`[${label}]`, obj);
    }
  }
};

En production, on utilise stringify avec un replacer qui supprime les propriétés privées (préfixées _). Les valeurs null passent tel quel. Les propriétés de type function sont automatiquement exclues par stringify — un avantage ici.

En développement, console.log affiche l’objet complet avec ses prototypes, ses fonctions et ses objets imbriqués. Les deux modes couvrent des besoins différents : traçabilité en prod, inspection libre en dev.

💡 Conseil : Ajoutez toJSON() sur vos classes métier. JSON.stringify appelle automatiquement toJSON() si la méthode existe sur l’objet. Cela vous donne un contrôle total sur les propriétés sérialisées, indépendamment de toString().

Pour les développeurs qui gèrent des tâches en remote, un logging structuré avec ces techniques rend le debug à distance nettement plus efficace — surtout quand console.dir() n’est pas disponible côté serveur.

La checklist anti [object Object]

Avant d’afficher ou de log un objet, passez par ces étapes :

  1. Vérifier null et undefinedif (value === null || value === undefined) avant tout accès aux propriétés. Un objet null n’a pas de prototype et lèvera une erreur.

  2. Identifier le contexte — Debug local → console.log(). UI → accéder aux propriétés par key. Transport API → JSON.stringify(). Chaque contexte a sa méthode.

  3. Éviter alert() pour le debugalert() convertit l’objet en string via le prototype toString(). Toujours. Sans exception. Préférez la console.

  4. Gérer les objets sans prototype — Un nullprotoobj n’a pas de toString(). Utilisez JSON.stringify() ou Object.prototype.toString.call() pour ces objets.

  5. Prévoir les références circulaires — Si votre objet peut contenir des références croisées, utilisez un safeStringify avec WeakSet. stringify standard lèvera une erreur.

  6. Filtrer les propriétés sensibles — En production, passez un replacer à stringify pour masquer les keys contenant des tokens, mots de passe ou données personnelles.

  7. Définir toString() sur vos classes — Un toString() personnalisé sur le prototype de vos objets évite le display générique [object Object] dans toute l’application.

// Exemple final : de [object Object] à un output lisible
const item = { name: "RTX 5090", price: 2199, stock: false };

// Mauvais :
alert(item);  // "[object Object]"

// Correct :
console.log(item);                    // objet interactif
console.log(JSON.stringify(item));    // '{"name":"RTX 5090","price":2199,"stock":false}'
console.log(item.name);              // "RTX 5090"

Pour les développeurs intéressés par le hardware derrière le code, le guide des tablettes Android ou le comparatif photo smartphone 2026 complètent bien cette approche logicielle avec un angle matériel.

FAQ

Qu’est-ce que [object Object] et d’où vient ce message ?

C’est la valeur retournée par Object.prototype.toString() quand JavaScript convertit un objet en string. Le premier « object » indique le type interne, le second « Object » est le tag par défaut. Ce n’est pas un message d’erreur — c’est le comportement normal du prototype racine. Pour voir les propriétés de l’objet, utilisez console.log() ou JSON.stringify().

Comment corriger [object Object] dans un alert ou dans le DOM ?

Remplacez alert(monObjet) par alert(JSON.stringify(monObjet, null, 2)) pour voir le contenu formaté. Pour le DOM, accédez directement aux propriétés : element.textContent = monObjet.name au lieu de element.textContent = monObjet. La key est de ne jamais laisser JavaScript convertir implicitement un objet en string.

Pourquoi JSON.stringify échoue sur certains objets (circular, null prototype) ?

JSON.stringify() lève une TypeError sur les références circulaires (deux objets qui se référencent mutuellement). Le correctif : un replacer avec WeakSet pour détecter les boucles. Pour les objets créés avec Object.create(null) (nullprotoobj), stringify fonctionne normalement — c’est toString() et hasOwnProperty() qui posent problème car le nullprotoobj n’a pas de prototype. Utilisez Object.hasOwn() (ES2022) ou Object.prototype.hasOwnProperty.call(nullprotoobj, key) pour tester les propriétés.

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.