Does Console.Log Invokes Tostring Method of an Object

Does console.log invokes toString method of an object?

Console API is not a standard API that is defined in any specification but is something that is implemented across all browsers, so vendors are usually at their liberty to implement in their own fashion as there's no standard spec to define the output of any methods in API.

Unless you check the actual implementation of the Console API for a particular browser, you can never be sure. There's a tracker on GitHub listing the differences between implementation from major browsers.

If you look at the implementation in FF (available here - search for log), it has a comment below

A multi line stringification of an object, designed for use by humans

The actual implementation checks for the type of argument that is passed to log() and based on it's type, it generates a different representation.

Coming to your case, log() prints two different values for strings created using literal notation and strings created using String constructor because they are two different types. As explained here, Strings created using literal notation are called String Primitives and strings created using String constructor are called String Objects.

var str1 = 'test';
var str2 = new String('hello');

typeof str1 // prints "string"
typeof str2 // prints "object"

As the types differ, their string representation differs in the Console API. If you go through the code for FF's Console implementation, the last statement is

return "  " + aThing.toString() + "\n";

So to answer your question, Console API in FF calls toString() on the argument only if the argument type is not one of {undefined,null,object,set,map} types. It doesn't always call toString() or valueOf() methods. I didn't check the implementation of Chrome, so I won't comment on that.

In Javascript, does console.log on an object call toString?

For Firefox(both Firebug and Dev Web Console), Chrome: No

For IE: Yes

Why console.log(obj) show structure of obj instead of return value of toString()

It is only for the good of debugging.

Would like to to see obj.toString() in console? Use:

Console.count(obj); //also will show how many times obj has been invoked

Usefull links:

  1. Firebug Console API
  2. Chrome Console API
  3. Mozilla Dev Docs

Recursion on console.log(this) in object specific method toString

Your toString method is calling console.log which may need (for its own displaying purposes) to stringify the argument you pass to it. But since that argument is this, it leads to a recursive call of toString (implicitly), and again, and again...

The purpose of toString is to return the string representation of your object, not to print it. If you really, really think it necessary (for debugging?) to use console.log inside the toString method, then don't pass this to console.log, but pass something that is already a string.

const object = {
toString() {
return "my object";
},
};

console.log(object.toString()); // my object

Why does function.toString() output [native code], whereas logging to the console directly displays the function’s source code?

It is because those functions have been passed to Function.prototype.bind.

> (function () { return 42; }).toString()
'function () { return 42; }'
> (function () { return 42; }).bind(this).toString()
'function () { [native code] }'

The bind method transforms an arbitrary function object into a so-called bound function. Invoking a bound function has the same effect as invoking the original function, except that the this parameter and a certain number of initial positional parameters (which may be zero) will have values fixed at the time of the creation of the bound function. Functionally, bind is mostly equivalent to:

Function.prototype.bind = function (boundThis, ...boundArgs) {
return (...args) => this.call(boundThis, ...boundArgs, ...args);
};

Except that the above will, of course, produce a different value after string conversion. Bound functions are specified to have the same string conversion behaviour as native functions, in accordance with ECMA-262 11th Ed., §19.2.3.5 ¶2:

2. If func is a bound function exotic object or a built-in function object, then return an implementation-dependent String source code representation of func. The representation must have the syntax of a NativeFunction. […]

[…]

NativeFunction:

function PropertyName [~Yield, ~Await] opt ( FormalParameters [~Yield, ~Await] ) { [native code] }

When printing the function to the console directly (instead of the stringification), the implementation is not bound to any specification: it may present the function in the console any way it wishes. Chromium’s console, when asked to print a bound function, simply displays the source code of the original unbound function, as a matter of convenience.


Proving that this is indeed what happens in YouTube’s case is a bit of a nuisance, since YouTube’s JavaScript is obfuscated, but not exceedingly difficult. We can open YouTube’s main site, then enter the developer console and install our trap:

window.setTimeout = ((oldSetTimeout) => {
return function (...args) {
if (/native code/.test(String(args[0])))
debugger;
return oldSetTimeout.call(this, ...args);
};
})(window.setTimeout);

We should get a hit at the debugger statement very quickly. I hit it in this function:

g.mh = function(a, b, c) {
if ("function" === typeof a)
c && (a = (0, g.D)(a, c));
else if (a && "function" == typeof a.handleEvent)
a = (0, g.D)(a.handleEvent, a);
else
throw Error("Invalid listener argument");
return 2147483647 < Number(b) ? -1 : g.C.setTimeout(a, b || 0)
}

The g.D function looks particularly interesting: it seems to be invoked with the first argument a, which is presumably a function. It looks like it might invoke bind under the hood. When I ask the console to inspect it, I get this:

> String(g.D)
"function(a,b,c){return a.call.apply(a.bind,arguments)}"

So while the process is a bit convoluted, we can clearly see that this is indeed what happens.

console.log formats error object different from Error.prototype.toString

console.log is unspecified, so each browser implements something different. (As does Node.js.) If you want to see exactly what, you can look at the browser source code, except for IE/Edge of course.

In Node.js, which I assume you are using because of the require, the code is:

  • console.log calls util.format
  • util.format calls an internal inspect function
  • which calls an internal formatValue function
  • which in this case calls an internal formatError function

    • which invokes Error.prototype.toString surrounded by braces
    • but also calls a formatter passing along the visible keys, thus giving the extra bits

Javascript: can't override toString method in very simple class?

Some browser might use toString for console.log, but some show the value in a more usable form. In Firefox for example you get a link to a view of the object properties.

If you use the object somewhere there a string is expected, it will use the ToString method that you specified:

function foo(arg) {    this.n=20;    this.x=arg;}
foo.prototype.toString = function(){ return this.x.toString();};
c = new foo(5);
document.write(c);


Related Topics



Leave a reply



Submit