149

When I console.log() an object in my JavaScript program, I just see the output [object Object], which is not very helpful in figuring out what object (or even what type of object) it is.

In C# I'm used to overriding ToString() to be able to customize the debugger representation of an object. Is there anything similar I can do in JavaScript?

Rap
  • 6,851
  • 3
  • 50
  • 88
devios1
  • 36,899
  • 45
  • 162
  • 260
  • 2
    I find that output is the most reliable way of telling you what a variable holds (or at least better than `typeof`). – alex Jun 10 '11 at 14:11

16 Answers16

122

You can override toString in Javascript as well. See example:

function Foo() {}

// toString override added to prototype of Foo class
Foo.prototype.toString = function() {
  return "[object Foo]";
}

var f = new Foo();
console.log("" + f); // console displays [object Foo]

See this discussion on how to determine object type name in JavaScript.

Mark Baijens
  • 13,028
  • 11
  • 47
  • 73
Michael Spector
  • 36,723
  • 6
  • 60
  • 88
  • 9
    While it is true the alert function will display the return value of the function overriding the prototype `toString` property, `Object.prototype.toString.call(f)` will still display `[object Object]`. – Frederik Krautwald May 12 '15 at 20:59
  • 25
    'Object.prototype.toString.call(f) will still display [object Object].' Yeah, because that's a completely different function than 'Foo.prototype.toString', lol. – Triynko Sep 09 '16 at 20:12
  • 11
    In case someone else like me ends up here, you can use Sybmol.toStringTag in ES6 to customize the Object.prototype.toString.call behavior. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag – TLadd Apr 16 '19 at 20:11
47

First override toString for your object or the prototype:

var Foo = function(){};
Foo.prototype.toString = function(){return 'Pity the Foo';};

var foo = new Foo();

Then convert to string to see the string representation of the object:

//using JS implicit type conversion
console.log('' + foo);

If you don't like the extra typing, you can create a function that logs string representations of its arguments to the console:

var puts = function(){
    var strings = Array.prototype.map.call(arguments, function(obj){
        return '' + obj;
    });
    console.log.apply(console, strings);
};

Usage:

puts(foo)  //logs 'Pity the Foo'

puts(foo, [1,2,3], {a: 2}) //logs 'Pity the Foo 1,2,3 [object Object]'

Update

E2015 provides much nicer syntax for this stuff, but you'll have to use a transpiler like Babel:

// override `toString`
class Foo {
  toString(){
    return 'Pity the Foo';
  }
}

const foo = new Foo();

// utility function for printing objects using their `toString` methods
const puts = (...any) => console.log(...any.map(String));

puts(foo); // logs 'Pity the Foo'
Max Heiber
  • 14,346
  • 12
  • 59
  • 97
17

If you are using Node it might be worth considering util.inspect.

var util = require('util')

const Point = {
  x: 1,
  y: 2,
  [util.inspect.custom]: function(depth) { return `{ #Point ${this.x},${this.y} }` }

}

console.log( Point );

This will yield:

{ #Point 1,2 }

While the version without inspect prints:

{ x: 1, y: 2 }

More information (+ an example for using in classes):

https://nodejs.org/api/util.html#util_util_inspect_custom

Mir-Ismaili
  • 13,974
  • 8
  • 82
  • 100
SystematicFrank
  • 16,555
  • 7
  • 56
  • 102
17

Add the 'Symbol.toStringTag' property to the custom object or class.

The string value which is assigned to it will be its default string description because it is accessed internally by the Object.prototype.toString() method.

For example:

class Person {
  constructor(name) {
    this.name = name
  }
  get [Symbol.toStringTag]() {
    return 'Person';
  }
}

let p = new Person('Dan');
Object.prototype.toString.call(p); // [object Person]

class Person {
  constructor(name) {
    this.name = name
  }
  get[Symbol.toStringTag]() {
    return 'Person';
  }
}

let p = new Person('Dan');
console.log(Object.prototype.toString.call(p));

Some Javascript types such as Maps and Promises have a built-in toStringTag symbol defined

Object.prototype.toString.call(new Map());       // "[object Map]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"

Because Symbol.toStringTag is a well-known symbol, we can reference it and verify that the above types do have the Symbol.toStringTag property -

new Map()[Symbol.toStringTag] // 'Map'
Promise.resolve()[Symbol.toStringTag] // 'Promise'
Danield
  • 121,619
  • 37
  • 226
  • 255
  • Is this together with overriding `toString()` directly the only way to achieve `function MyObj() {} Object.prototype.toString.call(new MyObj()) // "[object MyObj]"`? – tonix Mar 09 '20 at 07:43
  • 1
    @tonix - I think so... If there's another way, please let me know ;) – Danield Mar 09 '20 at 08:54
  • 1
    This should be the accepted answer for any code written in the last three or four years. As an aside, it's useful in mocking classes in unit tests so you can check the type of object you're instantiating. – David G Sep 23 '20 at 18:40
14

An easy way to get debuggable output in browser JS is to just serialize the object to JSON. So you could make a call like

console.log ("Blah: " + JSON.stringify(object));

So for an example, alert("Blah! " + JSON.stringify({key: "value"})); produces an alert with the text Blah! {"key":"value"}

Paul V
  • 1,272
  • 1
  • 8
  • 12
10

With template literals:

class Foo {
  toString() {
     return 'I am foo';
  }
}

const foo = new Foo();
console.log(`${foo}`); // 'I am foo'
sami
  • 101
  • 1
  • 2
7

If the object is defined by yourself you can always add a toString override.

//Defined car Object
var car = {
  type: "Fiat",
  model: 500,
  color: "white",
  //.toString() Override
  toString: function() {
    return this.type;
  }
};

//Various ways to test .toString() Override
console.log(car.toString());
console.log(car);
alert(car.toString());
alert(car);

//Defined carPlus Object
var carPlus = {
  type: "Fiat",
  model: 500,
  color: "white",
  //.toString() Override
  toString: function() {
    return 'type: ' + this.type + ', model: ' + this.model + ', color:  ' + this.color;
  }
};

//Various ways to test .toString() Override
console.log(carPlus.toString());
console.log(carPlus);
alert(carPlus.toString());
alert(carPlus);
Hacked Child
  • 91
  • 1
  • 5
6

Just override the toString() method.

Simple example:

var x = {foo: 1, bar: true, baz: 'quux'};
x.toString(); // returns "[object Object]"
x.toString = function () {
    var s = [];
    for (var k in this) {
        if (this.hasOwnProperty(k)) s.push(k + ':' + this[k]);
    }
    return '{' + s.join() + '}';
};
x.toString(); // returns something more useful

It does even better when you define a new type:

function X()
{
    this.foo = 1;
    this.bar = true;
    this.baz = 'quux';
}

X.prototype.toString = /* same function as before */

new X().toString(); // returns "{foo:1,bar:true,baz:quux}"
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 11
    This code does not solve the OP's console.log issue, at least not in node.js `v0.10.*` or Chrome `Version 32.0.1700.102`. While calling toString directly (lame) or using type coercion (lamer) will work with this, console[/info|log/] uses to old pre-mod toString. – james_womack Jan 29 '14 at 23:49
  • 1
    It's 2019 now and both nodejs and chrome pretty-print objects on their own, so coercion (when you add the object to a string) is the only use case you would google this question I believe. – Klesun Aug 13 '19 at 17:57
  • @Kleson People don't always search for what is possible, but what they dream is possible. Occasionally the answer is "You can't." – Ryan Leach Jun 10 '23 at 10:38
0

-This operation takes lot of time to complete, and it's use is discouraged according to mozilla docs: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

-Apparently, modern browsers deprecated .prototype and ECMA6 specifies using proper__proto__ instead.

So for example, if you are defining you own object geoposition you should call __proto__ property instead of .prototype:

var  geoposition = {

        lat: window.pos.lat,
        lng: window.pos.lng
    };

geoposition.__proto__.toString = function(){ return "lat: "+this.lat+", lng: "+this.lng }
console.log("Searching nearby donations to: "+geoposition.toString());
julianm
  • 2,393
  • 1
  • 23
  • 24
0

Here's an example how to stringify a Map object:

  Map.prototype.toString = function() {

    let result = {};

    this.forEach((key, value) => { result[key] = value;});

    return JSON.stringify(result);
  };
Agustí Sánchez
  • 10,455
  • 2
  • 34
  • 25
0

You can give any custom objects their own toString methods, or write a general one that you can call on the object you are looking at-

Function.prototype.named= function(ns){
    var Rx=  /function\s+([^(\s]+)\s*\(/, tem= this.toString().match(Rx) || "";
    if(tem) return tem[1];
    return 'unnamed constructor'
}

function whatsit(what){
    if(what===undefined)return 'undefined';
    if(what=== null) return 'null object';
    if(what== window) return 'Window object';
    if(what.nodeName){
        return 'html '+what.nodeName;
    }
    try{
        if(typeof what== 'object'){
            return what.constructor.named();
        }
    }
    catch(er){
        return 'Error reading Object constructor';
    }
    var w=typeof what;
    return w.charAt(0).toUpperCase()+w.substring(1);
}
kennebec
  • 102,654
  • 32
  • 106
  • 127
-1

You can't!

In 2023 Chrome doesn't base it's console output on anything you can control.

The best you can do, is output it to console.log lines which force object coercion.

Ryan Leach
  • 4,262
  • 5
  • 34
  • 71
-2

Rather than overriding toString(), if you include the Prototype JavaScript Library, you can use Object.inspect() to get a much more useful representation.

Most popular frameworks include something similar.

codelahoma
  • 895
  • 8
  • 14
-3

You can extend or override in JS

String.prototype.toString = function() {
    return this + "..."
}
document.write("Sergio".toString());
ch2o
  • 815
  • 2
  • 12
  • 29
-3

The Chrome console log allows you to inspect the object.

tomconte
  • 1,010
  • 8
  • 12
  • 1
    Yes, that's true if I output just the object, which is handy. However sometimes I just want to output it as part of a string that I might use to contain other data and it would be nice if I could customize that form in some manner. – devios1 Jun 10 '11 at 14:17
  • 7
    I just discovered that you can use additional arguments in a console.log to output objects inline with a string: `console.log("this is my object:", obj)`. – devios1 Feb 14 '12 at 15:14
-4
A simple format Date function using Javascript prototype, it can be used for your purpose

https://gist.github.com/cstipkovic/3983879 :

Date.prototype.formatDate = function (format) {
    var date = this,
        day = date.getDate(),
        month = date.getMonth() + 1,
        year = date.getFullYear(),
        hours = date.getHours(),
        minutes = date.getMinutes(),
        seconds = date.getSeconds();

    if (!format) {
        format = "MM/dd/yyyy";
    }

    format = format.replace("MM", month.toString().replace(/^(\d)$/, '0$1'));

    if (format.indexOf("yyyy") > -1) {
        format = format.replace("yyyy", year.toString());
    } else if (format.indexOf("yy") > -1) {
        format = format.replace("yy", year.toString().substr(2, 2));
    }

    format = format.replace("dd", day.toString().replace(/^(\d)$/, '0$1'));

    if (format.indexOf("t") > -1) {
        if (hours > 11) {
            format = format.replace("t", "pm");
        } else {
            format = format.replace("t", "am");
        }
    }

    if (format.indexOf("HH") > -1) {
        format = format.replace("HH", hours.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("hh") > -1) {
        if (hours > 12) {
            hours -= 12;
        }

        if (hours === 0) {
            hours = 12;
        }
        format = format.replace("hh", hours.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("mm") > -1) {
        format = format.replace("mm", minutes.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("ss") > -1) {
        format = format.replace("ss", seconds.toString().replace(/^(\d)$/, '0$1'));
    }

    return format;
};
aricca
  • 1
  • 1