Aller au contenu principal
12 min de lecture

Comprendre et corriger l'affichage [object Object] en JavaScript

Pourquoi JavaScript affiche [object Object] et comment corriger ce comportement. Mécanisme toString, prototype, JSON.stringify et solutions concrètes.

12 min de lecture
Partager
Comprendre et corriger l'affichage [object Object] en JavaScript

Comprendre et corriger l’affichage « [object Object] » en JavaScript

Un console.log qui retourne [object Object] au lieu du contenu attendu. Un alert qui affiche une chaîne incompréhensible. Un champ dans le DOM qui montre [object Object] à la place du nom d’un utilisateur. On a tous vu ça. Le problème n’est pas un bug — c’est le comportement par défaut du langage quand on tente de convertir un objet en string.

Cet article détaille la mécanique de conversion, les cas concrets où ça arrive, et les correctifs à copier-coller. Pas de théorie abstraite : du code, des résultats, des solutions.

« [object Object] » : ce que ça signifie vraiment

Quand on écrit un objet littéral en JavaScript — { name: "Alice", age: 30 } — ses propriétés sont accessibles par key. Mais dès qu’on force cet objet dans un contexte string (concaténation, template literal, alert), le moteur JS appelle automatiquement la méthode toString() héritée du prototype.

const user = { name: "Alice", age: 30 };
console.log("Utilisateur : " + user);
// Output : "Utilisateur : [object Object]"

Le résultat [object Object] est la representation par défaut. Le premier « object » (en minuscule) indique le type primitif. Le second « Object » (majuscule) correspond au constructeur — le name interne de l’objet tel que défini par Object.prototype.toString.

Ce n’est pas une erreur. C’est la réponse honnête du moteur : « tu m’as demandé une string, je t’ai donné la seule que je connaisse pour cet objet ».

Différence entre afficher un objet et afficher une string

console.log(user) et console.log("" + user) ne produisent pas le même output. Le premier laisse la console inspecter l’objet — on voit ses propriétés, ses key/value. Le second force une coercition string, et c’est là que [object Object] apparaît.

const config = { theme: "dark", lang: "fr" };
console.log(config);        // { theme: "dark", lang: "fr" } (inspectable)
console.log("" + config);   // "[object Object]"
console.log(`Config : ${config}`); // "Config : [object Object]"

La distinction est nette : l’objet lui-même contient toutes ses propriétés. La conversion string, elle, retourne une chaîne fixe parce que personne n’a défini comment la construire pour ce particular_object.

💡 Conseil : Quand [object Object] apparaît dans un log, remplacez "texte" + objet par console.log("texte", objet) (virgule au lieu du +). La console affiche alors l’objet de façon inspectable, avec ses propriétés dépliables.

La mécanique de conversion : prototype, toString et this

JavaScript suit un algorithme précis quand on use un objet dans un contexte qui attend une string. Trois étapes, dans l’ordre.

Étape 1 : le contexte string déclenche ToPrimitive

Concaténation avec +, template literals, alert(), document.title = objet — tous ces cas déclenchent l’opération interne ToPrimitive avec le hint "string". Le moteur cherche alors une méthode de conversion sur l’objet.

Étape 2 : valueOf et toString — qui passe en premier

Avec le hint "string", JS tente d’abord toString(), puis valueOf(). Sur un objet standard, valueOf() retourne l’objet lui-même (pas une valeur primitive), donc c’est toString() qui gagne.

const obj = { x: 1 };
console.log(obj.valueOf() === obj); // true — valueOf retourne l'objet
console.log(obj.toString());       // "[object Object]"

La méthode toString est héritée de Object.prototype. Elle n’est pas définie sur l’objet directement — c’est le prototype chain qui la fournit. D’où l’importance de comprendre comment le prototype fonctionne.

Pourquoi le name dans « [object Object] » est toujours « Object »

Object.prototype.toString utilise this pour accéder à l’objet appelant, puis retourne une string formatée [object <Tag>]. Le tag par défaut est "Object" — le name du constructeur.

const arr = [1, 2, 3];
console.log(Object.prototype.toString.call(arr));  // "[object Array]"
console.log(Object.prototype.toString.call(null));  // "[object Null]"
console.log(Object.prototype.toString.call("abc")); // "[object String]"

La méthode retourne toujours ce format. Pour un objet littéral, le tag est "Object". Pour un Array, "Array". Pour null, "Null". Le prototype détermine cette valeur — et on peut la personnaliser avec Symbol.toStringTag (on y revient plus bas).

📌 À retenir : [object Object] suit le format [object <ConstructorTag>]. Le tag vient de Symbol.toStringTag ou du type interne de l’objet. Sur un objet classique, c’est toujours "Object".

Quatre cas concrets où ça arrive : alert, console, DOM, concaténation

Cas 1 : alert(objet) affiche « [object Object] »

alert convertit son argument en string. Point. Pas d’inspection, pas de formatage.

const product = { name: "iPhone 16", price: 1229 };
alert(product);
// Affiche : "[object Object]"

alert(JSON.stringify(product));
// Affiche : '{"name":"iPhone 16","price":1229}'

alert(product.name + " — " + product.price + " €");
// Affiche : "iPhone 16 — 1229 €"

Trois lignes, trois résultats différents. Le premier force la coercition toString. Le deuxième utilise JSON.stringify pour sérialiser l’objet. Le troisième extrait les propriétés une par une — la méthode la plus propre pour un display lisible.

Cas 2 : console.log — deux comportements selon l’usage

const data = { id: 42, status: "active" };

console.log(data);           // Objet inspectable dans la console
console.log("Data: " + data); // "Data: [object Object]"
console.log("Data:", data);   // "Data:" suivi de l'objet inspectable

La virgule dans console.log sépare les arguments — chacun est affiché selon son type. Le + force la conversion en string avant même que log ne reçoive la valeur. C’est un piège classique.

Cas 3 : display dans le DOM (innerHTML, textContent)

const user = { name: "Bob", role: "admin" };
document.getElementById("info").textContent = user;
// Affiche dans la page : "[object Object]"

document.getElementById("info").textContent = user.name;
// Affiche : "Bob"

textContent et innerHTML attendent une string. L’objet subit la coercition, et le résultat est le même output [object Object]. La solution : toujours extraire la propriété spécifique qu’on veut afficher (par key).

Cas 4 : template literals et concaténation implicite

const settings = { mode: "dark", fontSize: 14 };
const msg = `Paramètres : ${settings}`;
console.log(msg);
// Output : "Paramètres : [object Object]"

const msg2 = `Paramètres : ${JSON.stringify(settings)}`;
console.log(msg2);
// Output : 'Paramètres : {"mode":"dark","fontSize":14}'

Les template literals appellent toString sur chaque expression interpolée. Même mécanique, même résultat. La méthode stringify est le fix le plus rapide pour du log ou du debug.

⚠️ Attention : JSON.stringify échoue silencieusement sur les fonctions, les Symbol et les références circulaires. Pour un objet avec des méthodes, le output sera incomplet — seules les propriétés sérialisables apparaissent.

Tableau de dépannage : du symptôme au correctif

SymptômeCauseFix
alert affiche [object Object]Coercition string implicitealert(JSON.stringify(obj)) ou alert(obj.name)
console.log affiche [object Object]Concaténation avec +Utiliser console.log("label", obj) (virgule)
DOM affiche [object Object]textContent = objExtraire la propriété : obj.name, obj.value
Template literal retourne [object Object]${obj} dans un backtick${JSON.stringify(obj)} ou ${obj.key}
Message d’erreur contient [object Object]Objet passé comme string dans un throwthrow new Error(JSON.stringify(obj))
Valeur null affiche "null" ou crashnull n’a pas de propriétésVérifier if (obj !== null) avant display

Fix rapide : console.log pour inspecter

La première chose à faire face à [object Object] : vérifier ce que contient l’objet.

const mystery = getApiResponse();
console.log(mystery);          // Inspecter dans la console
console.log(typeof mystery);   // Vérifier le type
console.log(Object.keys(mystery)); // Lister les propriétés

Object.keys() retourne un tableau de toutes les key propres (pas héritées du prototype). C’est le moyen le plus sûr de voir ce qu’un objet contient avant de l’afficher.

Fix affichage : JSON.stringify avec indentation

const order = { id: 7, items: ["laptop", "mouse"], total: 1549.99 };
const pretty = JSON.stringify(order, null, 2);
console.log(pretty);
// Output :
// {
//   "id": 7,
//   "items": ["laptop", "mouse"],
//   "total": 1549.99
// }

Le troisième argument de stringify contrôle l’indentation. null en deuxième position signifie « pas de function de remplacement ». Le résultat est une string lisible, copiable, loggable.

Fix durable : définir un toString() personnalisé

Quand un objet est affiché souvent, mieux vaut lui donner sa propre méthode toString plutôt que de répéter stringify partout.

function Product(name, price) {
  this.name = name;
  this.price = price;
}
Product.prototype.toString = function() {
  return `${this.name} (${this.price} €)`;
};

const p = new Product("Galaxy S26", 999);
alert(p);          // "Galaxy S26 (999 €)"
console.log("" + p); // "Galaxy S26 (999 €)"

Le prototype de Product a maintenant son propre toString. Chaque instance retourne une string lisible. Attention : ne jamais modifier Object.prototype.toString directement — ça affecterait tous les objets du programme. Toujours cibler le prototype du constructeur spécifique.

Fix robustesse : gérer null avant d’afficher

function displayUser(user) {
  if (user === null || user === undefined) {
    return "Aucun utilisateur";
  }
  return user.name || "Nom inconnu";
}

console.log(displayUser(null));    // "Aucun utilisateur"
console.log(displayUser({ name: "Eve" })); // "Eve"

Si la value est null, accéder à une propriété provoque un TypeError. Vérifier null et undefined en premier évite les crashs et les outputs inattendus.

Snippets prêts à l’emploi : log propre, stringify sûr, extraction key/value

Snippet 1 : prettyLog — affichage propre en console

function prettyLog(label, obj) {
  if (obj === null || obj === undefined) {
    console.log(label, String(obj));
    return;
  }
  console.log(label, JSON.stringify(obj, null, 2));
}

prettyLog("Config:", { theme: "dark", lang: "fr" });
// Output :
// Config: {
//   "theme": "dark",
//   "lang": "fr"
// }

Cette function gère null et undefined sans crash. Pour les objets, elle retourne une string formatée. Trois lignes de code qui évitent 90 % des [object Object] dans les logs.

Snippet 2 : safeStringify — références circulaires

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

const a = { name: "node" };
a.self = a; // Référence circulaire
console.log(safeStringify(a));
// Output :
// {
//   "name": "node",
//   "self": "[Circular]"
// }

JSON.stringify lance une TypeError sur les références circulaires. Cette function de remplacement (le deuxième argument) détecte les objets déjà visités et retourne un placeholder. Le Set stocke les references, le code reste compact.

Snippet 3 : lister les propriétés avec une boucle for

function listProperties(obj) {
  const result = [];
  for (const key of Object.keys(obj)) {
    const val = obj[key];
    const display = typeof val === "object" && val !== null
      ? JSON.stringify(val)
      : String(val);
    result.push(`${key}: ${display}`);
  }
  return result.join("\n");
}

const server = { host: "192.168.1.10", port: 8080, tags: ["prod", "eu"] };
console.log(listProperties(server));
// Output :
// host: 192.168.1.10
// port: 8080
// tags: ["prod","eu"]

Object.keys retourne les propriétés propres (pas celles du prototype). La boucle for...of itère chaque key, extrait la value, et construit une string lisible. Pour un objet imbriqué, stringify prend le relais.

Cas avancés : nullprotoobj, prototypes personnalisés et Symbol.toStringTag

Les objets à prototype null — pourquoi ils existent

Un objet créé avec Object.create(null) n’a aucun prototype. Zéro. Pas de toString, pas de hasOwnProperty, pas de valueOf. On les appelle parfois « nullprotoobj » dans les spécifications et les moteurs JS.

const dict = Object.create(null);
dict.foo = "bar";
dict.count = 42;

console.log(dict.toString);       // undefined — pas de prototype
console.log(dict.hasOwnProperty); // undefined — idem
console.log(dict + "");           // TypeError: Cannot convert object to primitive value

Un nullprotoobj provoque une TypeError à la conversion string — il n’a littéralement aucune méthode toString à appeler. Le prototype est null, la chaîne d’héritage est vide.

Pourquoi créer un tel objet ? Parce qu’il fonctionne comme un dictionnaire pur. Pas de propriétés héritées qui polluent les key. Si quelqu’un stocke une clé "toString" ou "constructor", ça n’écrase rien — il n’y a rien à écraser.

const safeDict = Object.create(null);
safeDict["toString"] = "cette value est juste du texte";
safeDict["constructor"] = 42;
// Aucun conflit avec le prototype — il n'y en a pas

// Pour afficher un nullprotoobj :
console.log(JSON.stringify(safeDict));
// Output : '{"toString":"cette value est juste du texte","constructor":42}'

📊 Chiffre clé : V8 (le moteur de Chrome/Node) crée en interne des nullprotoobj pour les caches de propriétés et les tables de symboles. C’est aussi le pattern derrière Object.create(null) qu’on retrouve dans des librairies comme Lodash pour les maps sans collision de key.

Vérifier si un nullprotoobj a une propriété

Sans hasOwnProperty sur le prototype, on utilise l’alternative sûre :

const npo = Object.create(null);
npo.x = 10;

// Méthode sûre — fonctionne sur tous les objets, y compris nullprotoobj
console.log(Object.prototype.hasOwnProperty.call(npo, "x")); // true
console.log(Object.prototype.hasOwnProperty.call(npo, "y")); // false

// Encore plus simple en ES2022+ :
console.log(Object.hasOwn(npo, "x")); // true

Object.hasOwn (ES2022) est la version moderne de hasOwnProperty — elle fonctionne sur n’importe quel objet, y compris les nullprotoobj. Le code est plus court et le comportement identique.

Personnaliser le tag avec Symbol.toStringTag

Object.prototype.toString lit la propriété Symbol.toStringTag pour déterminer le tag affiché dans [object <Tag>].

class ApiResponse {
  constructor(data) {
    this.data = data;
  }
  get [Symbol.toStringTag]() {
    return "ApiResponse";
  }
}

const resp = new ApiResponse({ status: 200 });
console.log(Object.prototype.toString.call(resp));
// Output : "[object ApiResponse]"

// Comparer avec un objet standard :
console.log(Object.prototype.toString.call({}));
// Output : "[object Object]"

Ce n’est pas cosmétique. Des bibliothèques comme Axios, les objets natifs Map, Set, Promise — tous définissent leur propre toStringTag. C’est la representation officielle du type dans le format [object ...].

Objets spéciaux : Date, Error, Map, Set

Chaque constructeur natif a son propre toString, et le résultat varie :

const d = new Date();
console.log("" + d);          // "Mon Feb 24 2026 10:30:00 GMT+0100"
console.log(Object.prototype.toString.call(d)); // "[object Date]"

const err = new Error("oops");
console.log("" + err);        // "Error: oops"
console.log(Object.prototype.toString.call(err)); // "[object Error]"

const m = new Map([["a", 1]]);
console.log("" + m);          // "[object Map]"
// Map n'a pas de toString personnalisé — retourne le format [object Map]

Date retourne une string lisible grâce à son propre prototype.toString. Error concatène le name et le message. Map et Set retournent [object Map] et [object Set] — pas de sérialisation automatique.

Pour afficher le contenu d’un Map :

const m = new Map([["host", "localhost"], ["port", 3000]]);
const entries = [...m.entries()];
console.log(JSON.stringify(Object.fromEntries(entries)));
// Output : '{"host":"localhost","port":3000}'

La conversion passe par Object.fromEntries qui crée un objet standard à partir des paires key/value du Map. Ensuite, stringify fait son travail.

Pour un Set :

const s = new Set([1, 2, 3]);
console.log(JSON.stringify([...s]));
// Output : "[1,2,3]"

Le spread operator [...s] convertit le Set en Array, et stringify sérialise le tableau. Deux lignes, output propre.

Quand on travaille avec du meilleur pc portable 2026 ou du matériel connecté, ces mécanismes de sérialisation reviennent constamment — les API REST renvoient des objets JSON, et les frameworks front-end les affichent dans le DOM.

Prototypes et héritage : pourquoi toString est partagé

Le système de prototype en JavaScript fonctionne comme une chaîne. Quand on accède à une propriété sur un objet, le moteur cherche d’abord sur l’objet lui-même, puis remonte la chaîne de prototypes jusqu’à Object.prototype (ou null pour un nullprotoobj).

const animal = { type: "dog" };
console.log(animal.toString === Object.prototype.toString); // true
// L'objet n'a pas de toString propre — il hérite du prototype

C’est pour ça que TOUS les objets standards retournent [object Object] par défaut : ils partagent la même méthode toString via le prototype. La propriété n’est pas copiée — elle est résolue dynamiquement via la chaîne.

Créer une instance avec un prototype personnalisé

function Device(name, brand) {
  this.name = name;
  this.brand = brand;
}

Device.prototype.toString = function() {
  return `${this.brand} ${this.name}`;
};

Device.prototype.toJSON = function() {
  return { name: this.name, brand: this.brand };
};

const phone = new Device("Pixel 9", "Google");
console.log("Appareil : " + phone);
// Output : "Appareil : Google Pixel 9"

console.log(JSON.stringify(phone));
// Output : '{"name":"Pixel 9","brand":"Google"}'

Définir toString sur le prototype du constructeur affecte toutes les instances. Le this binding fait référence à l’instance appelante — chaque objet retourne ses propres propriétés. La méthode toJSON contrôle le comportement de stringify pour cette classe.

Vérifier l’origine d’une méthode

const obj = { x: 1 };
console.log(obj.hasOwnProperty("x"));          // true — propriété propre
console.log(obj.hasOwnProperty("toString"));    // false — héritée du prototype
console.log(Object.hasOwn(obj, "toString"));    // false — idem, syntaxe moderne

hasOwnProperty (ou Object.hasOwn) distingue les propriétés propres des propriétés héritées du prototype. C’est utile pour itérer les key d’un objet sans inclure les méthodes héritées — typiquement dans une boucle for...in :

const data = { a: 1, b: 2 };
for (const key in data) {
  if (Object.hasOwn(data, key)) {
    console.log(key, data[key]);
  }
}
// Output :
// a 1
// b 2

Sans le garde hasOwn, la boucle for...in remonterait la chaîne de prototypes et pourrait retourner des propriétés inattendues.

Si on compare avec d’autres domaines tech — par exemple choisir un meilleur smartphone photo 2026 — la logique est la même : il faut comprendre ce qu’on inspecte avant de prendre une décision. En JavaScript, inspecter un objet avant de l’afficher évite 90 % des bugs liés à [object Object].

Gestion de null et undefined : les pièges de conversion

L’objet null n’est pas un objet. Ou plutôt, typeof null retourne "object" — un bug historique de JavaScript qui date de 1995 et qui ne sera jamais corrigé pour des raisons de rétrocompatibilité.

console.log(typeof null);       // "object" — mensonge historique
console.log(null === undefined); // false
console.log(null == undefined);  // true — coercition faible
console.log(String(null));       // "null"
console.log(String(undefined));  // "undefined"

Quand on tente d’accéder à une propriété sur null ou undefined, JavaScript lance un TypeError. Pas de toString, pas de prototype, pas de properties — rien.

const data = null;
// data.name → TypeError: Cannot read properties of null
// data.toString() → TypeError: Cannot read properties of null

// Fix : vérification avant accès
const name = data !== null && data !== undefined ? data.name : "N/A";
console.log(name); // "N/A"

Le chaînage optionnel (?.) simplifie la syntaxe :

const data = null;
console.log(data?.name);        // undefined (pas de crash)
console.log(data?.toString());   // undefined (pas de crash)
console.log(data?.name ?? "N/A"); // "N/A"

L’opérateur ?? (nullish coalescing) retourne la value de droite uniquement si la gauche est null ou undefined. C’est plus précis que || qui traite aussi 0, "" et false comme falsy.

⚠️ Attention : JSON.stringify(null) retourne la string "null" — pas une erreur. Mais JSON.stringify(undefined) retourne undefined (pas une string). Et dans un objet, les propriétés à undefined sont silencieusement omises par stringify.

console.log(JSON.stringify(null));      // "null"
console.log(JSON.stringify(undefined)); // undefined (pas "undefined")
console.log(JSON.stringify({ a: 1, b: undefined, c: null }));
// Output : '{"a":1,"c":null}'  — b est omis

Ce comportement est par design. stringify ne sérialise que les propriétés dont la value est un type JSON valide : string, number, boolean, null, object, array. Les fonctions, undefined et les Symbol sont ignorés.

Quand on développe des objets connectés pour la tablette android meilleur rapport qualité prix ou tout autre device, les réponses API contiennent souvent des champs null — et c’est exactement là que ces pièges de conversion surgissent.

Checklist de debug : du symptôme au correctif en 60 secondes

Voici la marche à suivre quand [object Object] apparaît quelque part dans le code :

  1. Identifier le contexte — Où apparaît la string ? Console, alert, DOM, template literal, message d’erreur ?
  2. Inspecter l’objetconsole.log(objet) avec une virgule, pas un +. Vérifier le type avec typeof.
  3. Lister les propriétésObject.keys(objet) pour voir les key disponibles.
  4. Choisir le fix adapté :
    • Affichage rapide → JSON.stringify(objet, null, 2)
    • Affichage ciblé → objet.name, objet.value, etc.
    • Affichage récurrent → Définir un toString() sur le prototype
    • Référence circulaire → Utiliser safeStringify (snippet ci-dessus)
  5. Gérer null — Toujours vérifier objet !== null avant d’accéder aux propriétés.
  6. Vérifier le prototype — Si l’objet est un nullprotoobj (Object.getPrototypeOf(obj) === null), utiliser stringify ou itérer manuellement les propriétés.
  7. Tester le output — Après le fix, vérifier que le résultat est bien une string lisible.
// Mini checklist en code :
function safeDisplay(obj) {
  if (obj === null || obj === undefined) return String(obj);
  if (typeof obj !== "object") return String(obj);
  if (typeof obj.toString === "function" && obj.toString !== Object.prototype.toString) {
    return obj.toString(); // toString personnalisé
  }
  return JSON.stringify(obj);
}

Cette function couvre tous les cas : null, undefined, primitives, objets avec toString custom, et objets standards. Huit lignes de code pour ne plus jamais voir [object Object] là où on ne le veut pas.

FAQ

Qu’est-ce que « [object Object] » en JavaScript ?

C’est la string retournée par Object.prototype.toString() quand un objet standard est converti en texte. Le format est [object <Tag>] où le tag correspond au type interne (Object, Array, Date, etc.). Ce n’est pas une erreur — c’est le comportement par défaut du prototype.

Comment résoudre l’erreur « [object Object] » dans un alert ou un log ?

Trois options selon le besoin. Pour du debug rapide : console.log("label", objet) (virgule, pas +). Pour un affichage complet : JSON.stringify(objet, null, 2). Pour un affichage ciblé : extraire la propriété directement (objet.name, objet.id). Si l’objet contient des références circulaires, utiliser une function safeStringify avec un Set de détection.

Pourquoi Object.create(null) provoque une TypeError à la conversion string ?

Un objet créé avec Object.create(null) — un nullprotoobj — n’a aucun prototype. Pas de toString, pas de valueOf. Quand JavaScript tente la coercition string (concaténation, template literal), il ne trouve aucune méthode de conversion et lance une TypeError. La solution : utiliser JSON.stringify ou définir manuellement une méthode toString sur l’objet (obj.toString = function() { ... }).

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.