Is it possible to override JavaScript's toString() function to provide meaningful output for debugging?

JavascriptDebuggingTostring

Javascript Problem Overview


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?

Javascript Solutions


Solution 1 - Javascript

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.

Solution 2 - Javascript

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'

Solution 3 - Javascript

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

Solution 4 - Javascript

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"}

Solution 5 - Javascript

With template literals:

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

const foo = new Foo();
console.log(`${foo}`); // 'I am foo'

Solution 6 - Javascript

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'

Solution 7 - Javascript

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}"

Solution 8 - Javascript

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

Solution 9 - Javascript

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

Solution 10 - Javascript

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

Solution 11 - Javascript

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

Solution 12 - Javascript

The Chrome console log allows you to inspect the object.

Solution 13 - Javascript

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.

Solution 14 - Javascript

You can extend or override in JS

String.prototype.toString = function() {
    return this + "..."
}
document.write("Sergio".toString());

Solution 15 - Javascript

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiondevios1View Question on Stackoverflow
Solution 1 - JavascriptMichael SpectorView Answer on Stackoverflow
Solution 2 - JavascriptMax HeiberView Answer on Stackoverflow
Solution 3 - JavascriptSystematicFrankView Answer on Stackoverflow
Solution 4 - JavascriptPaul VView Answer on Stackoverflow
Solution 5 - JavascriptsamiView Answer on Stackoverflow
Solution 6 - JavascriptDanieldView Answer on Stackoverflow
Solution 7 - JavascriptMatt BallView Answer on Stackoverflow
Solution 8 - JavascriptHacked ChildView Answer on Stackoverflow
Solution 9 - JavascriptkennebecView Answer on Stackoverflow
Solution 10 - JavascriptjulianmView Answer on Stackoverflow
Solution 11 - JavascriptAgustí SánchezView Answer on Stackoverflow
Solution 12 - JavascripttomconteView Answer on Stackoverflow
Solution 13 - JavascriptcodelahomaView Answer on Stackoverflow
Solution 14 - Javascriptch2oView Answer on Stackoverflow
Solution 15 - JavascriptariccaView Answer on Stackoverflow