Aller au contenu principal
logiciels-applications ·

Comprendre et corriger l'affichage « [object Object] » en JavaScript : causes, prototype chain et solutions

Pourquoi JavaScript affiche [object Object] dans alert, console ou le DOM. Prototype, toString, stringify : guide complet avec code reproductible.

Par La rédaction
Partager
Comprendre et corriger l'affichage « [object Object] » en JavaScript : causes, prototype chain et solutions

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

Quand on passe un objet JavaScript là où une string est attendue, le moteur appelle la méthode toString() héritée du prototype. Par défaut, Object.prototype.toString() retourne la chaîne "[object Object]". Rien de cassé : c’est la représentation textuelle standard de n’importe quel objet (object) dont le prototype n’a pas redéfini cette méthode.

Réponse courte : pourquoi cet output apparaît

Un objet n’est pas une string. Quand JavaScript doit convertir un objet en chaîne — concaténation, alert, template literal — il remonte la chaîne de prototype jusqu’à Object.prototype.toString. Cette function retourne "[object Object]", où le second « Object » est le tag interne de l’objet. Résultat : au lieu des propriétés qu’on espérait voir, on récupère cette représentation (representation) opaque.

Mini example :String(obj)etobj.toString()

const user

{ name: “Alice” , age: 32 }; console. log ( String (user));
// output : “[object Object]” console. log (user. toString ());
// output : “[object Object]” console. log ( JSON . stringify (user)); // output : ’{“name”:“Alice”,“age”:32}’

Les deux premières lignes produisent le même résultat parce que String() appelle toString() en interne. Seul JSON.stringify retourne quelque chose de lisible ici.

💡Conseil: dans 90 % des cas, remplaceralert(obj)paralert(JSON.stringify(obj, null, 2))suffit à débloquer la situation. Les 10 % restants concernent les objets circulaires — on y revient plus bas.

Quand JavaScript convertit un objet en string : les déclencheurs

Le problème ne vient jamais de l’objet lui-même. C’est le contexte d’utilisation qui force la conversion. Voici les quatre situations les plus courantes, avec le mécanisme exact en jeu.

Cas 1 :alert(obj)et concaténation"" + obj

alert() attend une string. Si on lui passe un objet, JavaScript applique l’algorithme ToPrimitive avec hint « string », ce qui déclenche toString(). La concaténation avec + fonctionne pareil dès qu’un des opérandes est une chaîne.

const config

{ key: “API_KEY” , value: “abc123” }; alert (config);
// affiche “[object Object]” alert ( “Config : ” + config); // affiche “Config : [object Object]“

Cas 2 : template literals${obj}

Les template literals appellent aussi toString() sur chaque expression interpolée. C’est le piège le plus fréquent dans du code moderne.

const item

{ name: “Clavier” , value: 89 }; console. log ( Article : ${ item } ); // log : “Article : [object Object]“

Cas 3 : DOM display (textContent/innerHTML)

Quand on assigne un objet à textContent, le navigateur convertit en string. Avec innerHTML, c’est pire : la chaîne "[object Object]" s’affiche directement dans le DOM.

const data

{ name: “Wattlet” , key: “tech” }; document. getElementById ( “output” ).textContent

data; // display dans le DOM : “[object Object]“

Cas 4 : logs (consolevs log serveur)

console.log(obj) dans un navigateur affiche un objet interactif — pas une string. Mais console.log("Résultat : " + obj) déclenche la concaténation et on retombe sur [object Object]. Côté serveur (Node.js), le log formatte selon util.inspect, ce qui donne un résultat différent.

const obj

{ prototype: “test” , key: “value” }; console. log (obj);
// objet interactif dans le navigateur console. log ( “Data : ” + obj); // log : “Data : [object Object]”

⚠️Attention: ne confondez pasconsole.log(obj)(inspection d’objet) etconsole.log(String(obj))(conversion en string). Le premier montre les propriétés, le second affiche[object Object].

Démonstration : alert vs console.log vs toString vs stringify

Prenons un objet simple et passons-le dans cinq méthodes de display. Le code ci-dessous est reproductible dans n’importe quelle console navigateur.

Example complet : mêmes données, 5 méthodes de display

const product

{ name: “Galaxy S26” , key: “smartphone” , value: 899 }; // 1. alert — force toString() alert (product); // output : “[object Object]” // 2. console.log — objet interactif console. log (product); // output dans la console : { name: “Galaxy S26”, key: “smartphone”, value: 899 } // 3. String() — toString() explicite console. log ( String (product)); // output : “[object Object]” // 4. toString() — appel direct console. log (product. toString ()); // output : “[object Object]” // 5. JSON.stringify — sérialisation console. log ( JSON . stringify (product)); // output : ’{“name”:“Galaxy S26”,“key”:“smartphone”,“value”:899}’

Cinq lignes de code, trois résultats différents. La méthode 2 (console.log direct) est la seule qui expose les propriétés de l’objet sans conversion.

Pourquoiconsole.log(obj)n’est pas équivalent àconsole.log(String(obj))

console.log est polymorphe. Quand il reçoit un objet (pas une string), il utilise un formatter interne qui affiche les propriétés sous forme d’arbre cliquable. Dès qu’on force la conversion — String(obj), concaténation, template literal — on perd cette inspection et on retombe sur Object.prototype.toString.

Un point que beaucoup de développeurs ignorent : dans Chrome, l’objet affiché par console.log est une référence live. Si on modifie l’objet après le log, l’affichage dans la console peut changer quand on déplie l’arbre. Pour capturer un snapshot, console.log(JSON.parse(JSON.stringify(obj))) fait le travail.

La vraie cause :Object.prototype.toString, prototype chain et le tag « Object »

Pour comprendre pourquoi cette string apparaît, il faut remonter la chaîne de prototype (prototype chain) de l’objet.

Chaîne de prototype : où se trouvetoString()

Tout objet créé avec {} ou new Object() hérite de Object.prototype. Ce prototype contient une trentaine de méthodes, dont toString(), hasOwnProperty(), valueOf(), et constructor. Quand on appelle obj.toString(), le moteur cherche d’abord une propriété toString sur l’objet lui-même. S’il n’en trouve pas, il remonte au prototype, puis au prototype du prototype, et ainsi de suite.

const obj

{ name: “test” }; console. log (obj. hasOwnProperty ( “toString” )); // false console. log (obj. hasOwnProperty ( “name” ));
// true // toString() vient du prototype, pas de l’objet

Pour la majorité des objets, la recherche s’arrête à Object.prototype.toString. Cette méthode retourne une string au format "[object Tag]".

Format”[object Type]”: d’où vient le name

Le tag « Object » dans [object Object] est déterminé par un mécanisme interne. Par défaut, les objets ordinaires ont le tag "Object". Les types natifs ont des tags spécifiques :

console. log ( Object . prototype .toString. call ([]));
// “[object Array]” console. log ( Object . prototype .toString. call ( null ));
// “[object Null]” console. log ( Object . prototype .toString. call ( undefined )); // “[object Undefined]” console. log ( Object . prototype .toString. call ( “abc” ));
// “[object String]” console. log ( Object . prototype .toString. call ( 42 ));
// “[object Number]” console. log ( Object . prototype .toString. call ( new Map ())); // “[object Map]”

C’est d’ailleurs pour ça que Object.prototype.toString.call() est utilisé comme méthode fiable de détection de type — bien plus précise que typeof.

Cas avancé :Symbol.toStringTag(particular_object)

Depuis ES2015, on peut personnaliser le tag via Symbol.toStringTag. Les objets natifs comme Map, Set, Promise l’utilisent déjà. Pour un objet custom :

const particular_object

{ [Symbol.toStringTag]: “MonObjet” , name: “demo” , value: 42 }; console. log ( Object . prototype .toString. call (particular_object)); // output : “[object MonObjet]”

Ce mécanisme ne change pas le comportement de JSON.stringify — seulement celui de toString.

Rôle dethisdans l’appel (méthode vs function)

Quand toString() est appelé comme méthode d’un objet (obj.toString()), this pointe vers cet objet. Mais si on extrait la function et qu’on l’appelle sans contexte, this pointe vers globalThis (ou undefined en mode strict). Ça change complètement l’output.

const obj

{ name: “test” }; const fn

obj.toString; console. log ( fn ()); // “[object Undefined]” en strict mode

Un piège classique avec this dans les callbacks : passer obj.toString comme argument à une function perd le binding.

Guide de résolution : tableau symptôme → cause → solution

Selon l’endroit où [object Object] apparaît, la solution diffère. Voici un tableau de correspondance directe, chaque entrée avec du code reproductible.

Si c’est dansalert(): afficher une key ou stringify

const user

{ name: “Bob” , key: “admin” , value: 1 }; // Problème alert (user); // “[object Object]” // Solution 1 : afficher une propriété alert (user.name); // “Bob” // Solution 2 : stringify complet alert ( JSON . stringify (user, null , 2 )); // output : ’{\n “name”: “Bob”,\n “key”: “admin”,\n “value”: 1\n}‘

Si c’est dans le DOM : contrôler la chaîne rendue

const product

{ name: “AirPods Pro 3” , value: 279 }; const el

document. getElementById ( “output” ); // Problème el.textContent

product; // display : “[object Object]” // Solution : formater la string manuellement el.textContent

${ product . name } — ${ product . value } € ; // display : “AirPods Pro 3 — 279 €“

Si c’est dansconsole/log : inspecter l’objet vs sérialiser

const data

{ name: “sensor” , properties: [ “temp” , “humidity” ], value: null }; // Inspection (recommandé pour le debug) console. log (data);
// objet interactif console. dir (data);
// arbre complet console. table ([data]);
// tableau formaté // Sérialisation (pour les logs serveur) console. log ( JSON . stringify (data));

📌À retenir:console.table()affiche les propriétés d’un objet (ou d’un tableau d’objets) sous forme de tableau HTML dans les DevTools. Pratique pour comparer 5-10 objets d’un coup — bien plus lisible qu’une série deconsole.log.

Si c’est dans une concaténation : corriger le code

const obj

{ name: “item” , value: 10 }; // Problème const msg

”Objet : ” + obj; // “Objet : [object Object]” // Solution const msg2

Objet : ${ obj . name } (${ obj . value }) ; // “Objet : item (10)”

La règle : ne jamais concaténer un objet avec une string sans extraire d’abord la propriété ou les propriétés voulues.

Solutions pratiques : accéder aux propriétés, custom toString, et inspection console

Afficher une propriété :obj.nameetobj[key]

L’approche la plus simple. On cible une key précise et on récupère sa valeur (value) :

const config

{ name: “prod” , key: “API_123” , value: “secret” }; console. log (config.name);
// “prod” console. log (config[ “key” ]);
// “API_123” // Accès dynamique avec une variable const prop

“value” ; console. log (config[prop]);
// “secret”

Afficher plusieurs values : formatage contrôlé

Pour afficher plusieurs propriétés, le destructuring combiné à un template literal retourne une string propre :

const { name , value }

config; const output

${ name } = ${ value } ; console. log (output); // “prod = secret”

On peut aussi boucler sur les clés (key) de l’objet :

for ( const key in config) { if ( Object . prototype .hasOwnProperty. call (config, key)) { console. log ( ${ key }: ${ config [ key ] } ); } }

CustomtoString(): quand c’est utile (et quand éviter)

Redéfinir toString() sur un objet (ou sur le prototype d’une classe) permet de contrôler l’output en cas de conversion :

function Device ( name , value ) { this .name

name; this .value

value; } Device . prototype . toString

function () { return ${ this . name } (${ this . value } €) ; }; const phone

new Device ( “Pixel 9” , 799 ); alert (phone);
// “Pixel 9 (799 €)” — plus de [object Object] console. log ( Tel : ${ phone } ); // “Tel : Pixel 9 (799 €)”

Utile pour les objets métier qu’on affiche souvent. À éviter sur des objets génériques ou éphémères — le jeu n’en vaut pas la chandelle.

hasOwnProperty: distinguer propriétés propres vs héritées

Quand on itère sur un objet avec for...in, la boucle remonte le prototype et inclut les propriétés héritées. hasOwnProperty (ou mieux, Object.hasOwn() depuis ES2022) filtre les propriétés propres :

const obj

Object. create ({ inherited: true }); obj.name

”test” ; obj.value

42 ; for ( const key in obj) { console. log (key, Object. hasOwn (obj, key)); // “name” true, “value” true, “inherited” false } // Alternative : Object.keys() retourne seulement les propriétés propres console. log (Object. keys (obj)); // [“name”, “value”]

Inspection :console.dir/console.table

console.dir affiche toutes les propriétés d’un objet, y compris celles du prototype. console.table formate un tableau :

const objets

[ { name: “MacBook Air M4” , value: 1299 , key: “laptop” }, { name: “iPad Pro M4” , value: 1199 , key: “tablet” } ]; console. table (objets); // Affiche un tableau avec colonnes name, value, key

Quand on travaille avec des logiciels et applications modernes, ces outils de debug deviennent vite indispensables.

JSON.stringify: comment l’utiliser, ce qu’il retourne, et ses limites

Ce queJSON.stringify(obj)retourne exactement

JSON.stringify retourne une string JSON valide. Pas une string « lisible » — une string parseable par JSON.parse. La function prend trois arguments : l’objet, un replacer optionnel, et un espacement :

const data

{ name: “test” , value: null , key: “abc” }; JSON . stringify (data);
// ’{“name”:“test”,“value”:null,“key”:“abc”}’ JSON . stringify (data, null , 2 );
// version indentée (2 espaces)

La valeur null est préservée telle quelle — c’est une valeur JSON valide.

Limites : objets circulaires, function, undefined, BigInt

Quatre situations où stringify échoue ou produit un résultat inattendu :

// 1. Objet circulaire → TypeError const a

{}; a.self

a; // JSON.stringify(a); // TypeError: circular // 2. function → ignorée const obj

{ name: “x” , fn : function () {} }; JSON . stringify (obj); // ’{“name”:“x”}’ — fn disparaît // 3. undefined → ignoré dans les objets, null dans les arrays const obj2

{ name: “x” , value: undefined }; JSON . stringify (obj2); // ’{“name”:“x”}’ // 4. BigInt → TypeError // JSON.stringify({ n: 42n }); // TypeError

Replacer : filtrer/transformer des properties

Le deuxième argument de stringify est un replacer. En passant un tableau, on sélectionne les key à inclure. En passant une function, on transforme chaque value :

const obj

{ name: “secret” , key: “API_KEY” , value: “abc123” , internal: true }; // Filtrer par key JSON . stringify (obj, [ “name” , “value” ]); // ’{“name”:“secret”,“value”:“abc123”}’ // Transformer JSON . stringify (obj, ( key , value ) => { if (key

“key” ) return “[HIDDEN]” ; return value; }); // ’{“name”:“secret”,“key”:“[HIDDEN]”,“value”:“abc123”,“internal”:true}‘

Safe stringify : stratégie simple avec Set

Pour les objets potentiellement circulaires, un Set de références déjà vues fait office de garde-fou :

function safeStringify ( obj ) { const seen

new Set (); return JSON . stringify (obj, ( key , value ) => { if ( typeof value

”object” && value !== null ) { if (seen. has (value)) return “[Circulaire]” ; seen. add (value); } return value; }, 2 ); } const circular

{ name: “loop” , value: null }; circular.self

circular; console. log ( safeStringify (circular)); // output : ’{ “name”: “loop”, “value”: null, “self”: “[Circulaire]” }’

C’est une technique qu’on retrouve dans pas mal de librairies de logging Node.js.

Complétez votre lecture avec notre guide détaillé sur « [object Object] ».

Cas avancés : objets avec prototype null (nullprotoobj) et pièges liés ànull

Ce sujet est rarement couvert dans les tutos. Les objets sans prototype existent, et leur comportement face à toString est radicalement différent.

Retrouvez aussi notre dossier complet : un dossier dédié à l’affichage de [object Object].

Object.create(null): pourquoi il n’y a pas de prototype

Object.create(null) crée un objet dont le prototype est null. Pas Object.prototype — littéralement null. Cet objet (qu’on appelle « nullprotoobj » ou « dictionary object ») n’hérite d’aucune méthode.

const nullprotoobj

Object. create ( null ); nullprotoobj.name

”bare” ; nullprotoobj.value

42 ; console. log (Object. getPrototypeOf (nullprotoobj)); // null

On croise ces objets dans les caches, les dictionnaires, et les parseurs. Leur avantage : aucune collision avec les propriétés héritées du prototype (constructor, toString, hasOwnProperty).

Conséquences : pas detoString(), pas dehasOwnProperty()

Un nullprotoobj ne possède ni toString ni hasOwnProperty ni aucune des méthodes habituelles. Tenter d’appeler ces méthodes déclenche une TypeError :

const nullprotoobj

Object. create ( null ); nullprotoobj.name

”bare” ; nullprotoobj.key

“test” ; // nullprotoobj.toString(); // TypeError: nullprotoobj.toString is not a function // nullprotoobj.hasOwnProperty(“name”); // TypeError // Vérifier les propriétés sans hasOwnProperty : console. log (Object. keys (nullprotoobj)); // [“name”, “key”] console. log ( “name” in nullprotoobj);
// true

Pour un convertisseur YouTube MP4 en JavaScript côté client, ce genre de piège arrive quand on manipule des objets parsés depuis des sources externes.

Solution :Object.prototype.toString.call(nullprotoobj)

On peut forcer l’appel à toString en passant le nullprotoobj comme contexte via call :

const nullprotoobj

Object. create ( null ); nullprotoobj.name

“dict” ; console. log ( Object . prototype .toString. call (nullprotoobj)); // output : “[object Object]” // stringify fonctionne normalement console. log ( JSON . stringify (nullprotoobj)); // output : ’{“name”:“dict”}’

JSON.stringify n’a pas besoin de toString pour fonctionner — il accède directement aux propriétés énumérables de l’objet. C’est la méthode la plus fiable pour sérialiser un nullprotoobj.

nullvs objet : éviter les erreurs d’accès aux propriétés

typeof null retourne "object" — un bug historique de JavaScript qui remonte à 1995 et qui ne sera jamais corrigé (trop de code dépend de ce comportement). Conséquence : tester typeof x === "object" ne suffit pas pour garantir qu’on a un objet avec des propriétés.

const values

[ null , undefined , {}, Object. create ( null ), { name: “ok” }]; for ( const val of values) { if (val !== null && typeof val

“object” ) { // Safe : on sait que val est un objet (pas null) console. log (Object. keys (val)); } }

Toujours tester null avant d’accéder aux propriétés d’un objet. Chaîner obj?.propriete (optional chaining) est l’approche moderne — disponible dans tous les navigateurs depuis 2020.

📊Chiffre clé: selon le State of JS 2024, 87 % des développeurs JavaScript utilisent l’optional chaining (?.) en production. Le null check explicite reste la méthode recommandée dans les environnements sans transpilation.

Checklist de debug : retrouver la source de « [object Object] »

Quand on tombe sur [object Object] dans une app, le réflexe est de tracer l’origine. Six étapes suffisent dans la majorité des cas.

Étapes rapides (6 points) pour isoler la cause

  1. Localiser l’output — est-ce dans le DOM, une alerte (alert), la console, un log serveur ?
  2. Vérifier le typetypeof suspect === "object" et suspect !== null
  3. Lister les propriétésObject.keys(suspect) pour voir les key disponibles
  4. Vérifier le prototypeObject.getPrototypeOf(suspect) : est-ce null (nullprotoobj), Object.prototype, ou un prototype custom ?
  5. Vérifier this — si c’est dans une méthode ou un callback, le contexte this est-il correct ?
  6. Choisir la bonne stratégie — inspection console (debug) vs JSON.stringify (log) vs accès direct à une propriété (display)

Snippet diagnostic : typeof, null-check, prototype, keys

function diagnose ( obj ) { console. log ( “Type :” , typeof obj); console. log ( “Est null :” , obj

null ); if (obj !== null && typeof obj

“object” ) { console. log ( “Prototype :” , Object. getPrototypeOf (obj)); console. log ( “Keys :” , Object. keys (obj)); console. log ( “Propriétés (count) :” , Object. keys (obj). length ); console. log ( “toString retourne :” , Object . prototype .toString. call (obj)); try { console. log ( “stringify :” , JSON . stringify (obj)); } catch (e) { console. log ( “stringify erreur :” , e.message); } } } // Use : diagnose ({ name: “test” , value: 1 }); diagnose ( null ); diagnose (Object. create ( null ));

Ce snippet couvre les trois cas problématiques : objet normal, null, et nullprotoobj. Il retourne des informations exploitables pour chaque situation.

Des réflexes similaires s’appliquent quand on débogue des outils côté tablette Android ou qu’on teste une application sur smartphone — la console Chrome DevTools en remote fonctionne exactement pareil.

FAQ : questions fréquentes sur « [object Object] »

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

C’est la string que retourne Object.prototype.toString() quand on convertit un objet en chaîne. Le premier « object » (minuscule) est fixe, le second « Object » (majuscule) est le tag interne du type. Pour voir les propriétés de l’objet, on accède directement à une key (obj.name) ou on sérialise avec JSON.stringify(obj).

Pourquoialert(obj)affiche « [object Object] » alors queconsole.log(obj)montre les propriétés ?

alert() convertit tout en string avant d’afficher — d’où l’appel à toString() et le résultat [object Object]. console.log, lui, détecte qu’il reçoit un objet et utilise un formatter spécial qui affiche les propriétés de manière interactive. Pour afficher un objet dans une alerte : alert(JSON.stringify(obj, null, 2)).

Comment gérer un objet sans prototype (nullprotoobj) qui n’a pas detoString?

Un nullprotoobj créé via Object.create(null) ne possède aucune méthode héritée — ni toString, ni hasOwnProperty. Pour le convertir en string : Object.prototype.toString.call(nullprotoobj) retourne "[object Object]". Pour le sérialiser : JSON.stringify(nullprotoobj) fonctionne normalement car stringify accède aux propriétés énumérables sans passer par le prototype. Pour lister les key : Object.keys(nullprotoobj).

Récapitulatif : les 5 réflexes pour ne plus subir « [object Object] »

Pas besoin de relire les 1 500 mots au-dessus. Les règles tiennent en cinq points :

  • [object Object] = conversion automatique en string. L’objet n’est pas corrompu — JavaScript fait juste ce qu’on lui demande (mal).
  • Pour inspecter : console.log(obj) sans concaténation. console.dir et console.table pour les cas avancés.
  • Pour afficher : accéder à une propriété spécifique (obj.name, obj[key]) ou formater avec un template literal après extraction.
  • Pour sérialiser : JSON.stringify(obj) avec gestion des limites (objets circulaires via safe stringify, function ignorées, null préservé).
  • Cas spéciaux : vérifier le prototype (nullprotoobj sans méthodes), le contexte this (binding perdu dans les callbacks), et toujours tester null avant d’accéder aux propriétés d’un objet.

Si le sujet du management des outils numériques ou du travail à distance vous intéresse, ces compétences de debug JavaScript sont exactement le genre de savoir-faire technique qui fait la différence au quotidien.

Articles similaires

Questions frequentes

Qu’est-ce que « [object Object] » en JavaScript ?
C’est la string que retourne `Object.prototype.toString()` quand on convertit un objet en chaîne. Le premier « object » (minuscule) est fixe, le second « Object » (majuscule) est le tag interne du type. Pour voir les propriétés de l’objet, on accède directement à une key (`obj.name`) ou on sérialise avec `JSON.stringify(obj)`.
Pourquoialert(obj)affiche « [object Object] » alors queconsole.log(obj)montre les propriétés ?
`alert()` convertit tout en string avant d’afficher — d’où l’appel à `toString()` et le résultat `[object Object]`. `console.log`, lui, détecte qu’il reçoit un objet et utilise un formatter spécial qui affiche les propriétés de manière interactive. Pour afficher un objet dans une alerte : `alert(JSON.stringify(obj, null, 2))`.
Comment gérer un objet sans prototype (nullprotoobj) qui n’a pas detoString?
Un nullprotoobj créé via `Object.create(null)` ne possède aucune méthode héritée — ni `toString`, ni `hasOwnProperty`. Pour le convertir en string : `Object.prototype.toString.call(nullprotoobj)` retourne `"[object Object]"`. Pour le sérialiser : `JSON.stringify(nullprotoobj)` fonctionne normalement car stringify accède aux propriétés énumérables sans passer par le prototype. Pour lister les key : `Object.keys(nullprotoobj)`.
La rédaction

La rédaction

Ingénieur thermicien de formation (INSA Lyon, 2009), passé par le bureau d'études d'EDF puis par le conseil en stratégie énergie-climat. Il a fondé Wattlet pour créer un média qui part de la physique, pas de l'opinion.

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