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:
- Firebug Console API
- Chrome Console API
- 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
- which invokes
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
How to Add Predefined Length to Audio Recorded from Mediarecorder in Chrome
JavaScript - Convert Array of Arrays into Array of Objects with Prefilled Values
Jquery - Get Text for Element Without Children Text
How to Break/Exit from a Each() Function in Jquery
Jquery Equivalent of JavaScript's Addeventlistener Method
Firestore: What's the Pattern for Adding New Data in Web V9
Check Whether an Array Exists in an Array of Arrays
Es6 Promise.All() Error Handle - Is .Settle() Needed
How to Get a JavaScript Object Property Name That Starts with a Number
Detect iPad Users Using Jquery
Order of Hoisting in JavaScript
Setting Multiple Attributes for an Element at Once with JavaScript
Is There Any Difference Between Declared and Defined Variable
Finding Closest Element Without Jquery
Getting All Selected Checkboxes in an Array
How to Sort an Array of Objects Based on the Ordering of Another Array
What Is the List of Possible Values for Navigator.Platform as of Today