Minor note: I'm very familiar with console.log()
, JSON.stringify()
, Object.prototype.toString()
, util.inspect()
etc - this question isn't asking how to show the contents of objects, but rather why node's behavior changes in different circumstances.
I know I can console.log(someObject)
and node will print:
[object Object]
node js function return [object Object] instead of a string value has some good information on this.
I know that [object Object]
is from Object.prototype.toString()
I know I can console.log(JSON.stringify(someObject, null, 2)
and node will print:
{
foo: 'bar'
}
Or use util.inspect()
etc. See this answer
However it seems that sometimes node will actually print the objects contents
If I make a new file called runme.js
with the contents:
console.log({foo: 'bar'})
And run node runme.js
node will print
{ foo: 'bar' }
Not [object Object]
Why is node not printing [object Object]
?
Edit: per Keith's question, [object Object]
will appear when I run:
console.log(`Check me out ${{foo: 'bar'}}`)
Logs [object Object]
What determines whether node uses Object.prototype.toString()
(aka [object Object]
) vs printing the contents of the object?
Minor note: I'm very familiar with console.log()
, JSON.stringify()
, Object.prototype.toString()
, util.inspect()
etc - this question isn't asking how to show the contents of objects, but rather why node's behavior changes in different circumstances.
I know I can console.log(someObject)
and node will print:
[object Object]
node js function return [object Object] instead of a string value has some good information on this.
I know that [object Object]
is from Object.prototype.toString()
I know I can console.log(JSON.stringify(someObject, null, 2)
and node will print:
{
foo: 'bar'
}
Or use util.inspect()
etc. See this answer
However it seems that sometimes node will actually print the objects contents
If I make a new file called runme.js
with the contents:
console.log({foo: 'bar'})
And run node runme.js
node will print
{ foo: 'bar' }
Not [object Object]
Why is node not printing [object Object]
?
Edit: per Keith's question, [object Object]
will appear when I run:
console.log(`Check me out ${{foo: 'bar'}}`)
Logs [object Object]
What determines whether node uses Object.prototype.toString()
(aka [object Object]
) vs printing the contents of the object?
-
1
Have you an example of someObject that does this, as that might help. eg.
{foo: 'bar'}
would work fine anyway without using stringify.. – Keith Commented Oct 27, 2020 at 10:49 -
1
Does the object implement the
nodejs.util.inspect.custom
symbol method? – VLAZ Commented Oct 27, 2020 at 10:57 -
@Keith added an example. Per the answers, looks like the ES6 string literal was running the
toString()
before theconsole.log
could do anything, – mikemaccana Commented Oct 27, 2020 at 11:12 - @VLAZ no it doesn't. Good question though! – mikemaccana Commented Oct 27, 2020 at 11:14
- Yes, that makes sense why it's [object Object], in theory though you could create your own template literal parser to show it differently.. – Keith Commented Oct 27, 2020 at 11:17
3 Answers
Reset to default 5Console logging will output [object Object]
for an object value that was converted to a string before being passed as a parameter to a console method, or if an object value argument is consumed and inserted into a format string passed as the first argument.
The latter occurs if a format string contains C-like percentage prefixed conversion sequences within it that consume the next unused argument and embed it the format string.
If a format string is used, and more (object) arguments are passed to the method than are used by the format string, remaining unconsumed arguments that are objects are logged as object values without conversion to strings.
So some expected values and actual log output:
const someObject = {a: "a"};
// expected output: "string [object Object]"
console.log( "string " + someObject);
// expected output: "same deal: [object Object]"
console.log( "same deal: %s", someObject); // converted by format string
// expected output: 'someObject = {a: "a"}'
console.log( "someObject = ", someObject) // someObject was not consumed by format string!
Of course Node does not present an interactive object view on the text console, and in simple cases it can look a lot like JSON.stringify()
output. However Node does make an attempt to
- identify the constructor of the object,
- color code values according to their data type
- handle presentation of circular references
that expand its debugging potential beyond simple JSON.stringify()
conversions.
In my experience, console.log
detects when it is passed the object and prints the entire object like the example you showed.
console.log({foo: 'bar'})
// => { foo: 'bar' }
However when an object is concatenated to a string, it's converted to a string using the .toString()
method and then passed to the console.log
method.
Example:
console.log('' + { foo: 'bar' })
// => [object Object]
This is because before passing to console.log method, the expression is evaluated to '' + { foo: 'bar' }.toString()
.
That's my understanding of how it works. Though the internal workings might be more plex.
As has been worked out, template literals will box the args using .toString.
But if you find you use template literals a lot for debugging, and you want to use JSON.stringify instead.
Here is a simple example below.
function tagJSON(strings, ...args) {
const output = [];
let nextString = 0;
let nextArg = 0;
//loop all string & args
while (nextArg < args.length) {
output.push( strings[nextString] );
output.push( JSON.stringify(args[nextArg]) );
nextArg += 1;
nextString += 1;
}
//might be a string left at the end..
if (nextString < strings.length)
output.push( strings[nextString] );
//finally output our new concated string & stringified(args)
return output.join('');
}
var someobject = {x: 'y'};
let output = tagJSON`someobject = ${someobject}`;
console.log(output);
console.log(tagJSON`boolean = ${true} or ${false}`);
console.log(tagJSON`strings will double quote ${'hello world'}`);