What Console.Log Really Prints

Here’s a quick lesson for you: In your web browser’s devtools, your console.log() does not capture the objects you print when you print them. It captures it when you look at the printout.

Okay, that’s pretty weird. Let me back up.

Recently, while debugging, I added a couple of printouts to my code and got some bizarre results. Here’s what I wrote:


And here’s what I saw:

How can that be? Two print statements, one right after another. They ran together, yet when I drilled down into the user object (from the first line of the printout), the array of blogPostIds had a different value.

Sidebar: Printing Circular Objects

To understand what’s happening here, let me jump temporarily to a different example. Consider this code:

const object1 = {};
const object2 = { referenceToObject1: object1 };
object1.referenceToObject2 = object2;

The object here contains a reference to itself: object1 references object2, which points right back to object1. What would you expect printing it to do? It would be reasonable to guess this might crash (perhaps with a stack overflow as it recurses through the object for printing.) Or perhaps it would fill the screen with JSON output.

Except… it doesn’t. It works just fine:

Note that the screenshot is from Firefox. Chrome’s devtools also works but displays a bit differently.

What’s happening here is that the developer tools in modern browsers work pretty hard to let you browse objects smartly, one layer at a time. Because it doesn’t try to walk and print the entire object graph, it can handle circular data structures. Generally, this is great! It means you can print things with wild abandon and explore pretty much any object you can get your hands on, and they’ll print out in a reasonable way.

But if, instead of printing out the object, you tried to print the object after serialization, it would blow up with something like Uncaught TypeError: Converting circular structure to JSON.

Printing by Reference

We can see from the above that the browser doesn’t evaluate objects right when we print them. Instead, the rule is: console.log evaluates only one level when printing, and each level deeper you click into is evaluated as you click.

So printing user.blogPostIds captures the array when it’s logged (because it’s the top-level reference), but clicking into blogPostIds from a printed user record doesn’t evaluate blogPostIds until you click on it.

If you suspect that you’re seeing this behavior, there are two simple solutions:

  • Serialize the object before printing by running `console.log(JSON.stringify(myObject))`. That will lose the nice interactive tools, but the benefit is that you can be confident you’re seeing all the values from when it was serialized.
  • Use a debugger (such as this).

I generated the above examples in CodePen. You can try it for yourself there.