JavaScript Console - Deep Dive

Piotr Pliszko

JavaScript developers use console on daily basis. Nonetheless, a lot of them use only basic methods like log, debug and error. Console has a lot of functionalities besides those - their appropriate usage can help us debug faster and more effectively. In this article I want to dive deep into console and explore it’s abilities.

About console and window.console

Console in JavaScript is accessible via console or window.console object. Using console object is safer in multi-environment codebase. In a browser environment, console is the global variable and it refers to window.console object. In a non-browser environments it’s not always true. For example, node.js uses global object instead of window. In environments where window is not defined, window.console will fail where console.log wouldn’t (provided the environment provides a global console object).

Basic logging with log

console.log() is the most used method of console. It outputs provided message to the browser's console. The message may be a string, an object or more than one JavaScript objects.

Examples:

console.log('test');
const testObject = { a: 1, b: 2, c: 3 };
console.log(testObject);

Logging objects

Using console.log(obj) is totally fine - if you want to check value of an object now. If you would like to log current state of an object to refer to it later, you may encounter some strange behaviour. Many browsers provide live view that constantly updates as variable values change, so after expanding logged object in the browser console, you may see current state of this object, not the state at the moment of logging it. For simple objects we could just avoid expanding them, but it's not really possible when working with complex objects. Let's see how it works:

1

As we can see, before I expanded logged object, c value was 3, as it was at the time of logging it. But after expanding logged object, browser reloaded values using current state of variable and c changed to current value. It's probably not what you would want to see when referring to object logged at the past, so let's fix this. To see state of the object at the moment you log it, you must pass copy of the object to console. To do this, you can use JSON.parse and JSON.stringify:

console.log(JSON.parse(JSON.stringify(obj)));
2

After expanding we can see the values we are interested in.

Logging HTML elements with dir

You can log HTML elements using log objects, but it prints the element in an HTML-like tree. If you want to print it in JSON-like tree use dir.

Firefox console example:

3

Chrome console example:

4

String substitutions

When passing a string to one of the console methods that accepts a string, you can use substitution strings.

To log a string, you can use %s:

const nameObject = { name: 'John' };
console.log('His name is %s Watson', nameObject.name);
5

This is equivalent to

console.log('His name is', nameObject.name, 'Watson');
console.log(`His name is ${nameObject.name} Watson`);
6

To log an object use %o or %O.

7

Using %d or %i allows us to log an integer.

8

Logging floating-point values requires %f.

9

If you try to use %d with floating-point value, decimals are omitted.

10

Log levels - info, warn and error

info, warn and error methods are similar to log - only differences are in message presentation. log and info messages are usually displayed without any special indicators. warn and error messages are visually differentiated, they have different styling and stack trace output.

Firefox console example:

11

Chrome console example:

12

Huge benefit of using warn and error is ability to filter out less important messages using browser’s console filtering capabilities. Let's have a look at log level filtering in Google Chrome console:

13 14

Browsing tabular data with table

One of the most useful tools in JavaScript console is the table method. It allows for clear and readable data presentation, usually much better than raw object. You can use it to present arrays and objects.

const person = { name: 'John', lastName: 'Watson' };
console.table(person);
15

Not really useful for this simple object. But let's have a look at an array:

const arr = ['John', 'Sherlock'];
console.table(arr);
16

and an array of objects:

const data = [
  { name: 'John', lastName: 'Watson' },
  { name: 'Sherlock', lastName: 'Holmes' },
];
console.table(data);
17

With data getting more complex, table starts to show it's usefulness.

Sorting columns

Some browsers allow us to sort table columns. You can do this by clicking at the column name.

18

Filtering data

Sometimes objects can be very complex. If you want to present only essential data in our table you can use filtering. Just pass an array of desired properties to table:

console.table(obj, ['first', 'second']);

For example:

const data = [
  { name: 'John', lastName: 'Watson' },
  { name: 'Sherlock', lastName: 'Holmes' },
];
console.table(data);
console.table(data, ['name']);
19

Counting iterations with count

This method logs the number of times it has been called with specific parameter. For example:

for (let i = 0; i < 10; i++) {
  console.count('iteration');
}
20

Measuring time using time

I’ve seen many times measuring script execution time like this:

const start = new Date().getTime();
// ...
const end = new Date().getTime() - start;

then computing miliseconds. It’s neither handy nor quick, but again - JavaScript console comes in handy! time is a dedicated function to track execution time. Just give it a unique name, for example:

console.time('test');
// ...
console.timeEnd('test');
21

You can have multiple timers up and running at once. According to MDN - up to 10000, but I have tested it and managed to create 100000 timers on Chrome on macOS, while page still worked smoothly.

Grouping data with group

In my opinion this is incredibly useful feature. Many times I have seen applications logging tons of information, but it was very hard to find something in this clutter. Clever usage of this method could help us with this issue - grouping related data is a true game changer in terms of console readability. Let's take a look at this simple example:

22

You can also use groupCollapsed to log initially collapsed groups:

23

trace

If you want to know where the log is being prompted from you can use trace() method. For example, if you call this method from inside of Angular you can expect output like below.

handleBlur($event: FocusEvent) {
  console.trace();
  // ...
}
24

If you call it in browser console, you will see it shows only one, (anonymous) step.

25

Styling console output with custom CSS

You can pass CSS properties to console.log() and other console methods. Input parameter with %c in the beginning allows us to inject CSS as a second parameter to log() method. For example:

console.log('%ctest', 'color: red; font-size: 30px;');
26

You can also pass different CSS properties for part of the text with multiple %c:

console.log(
  '%ctest%ctest',
  'color: red; font-size: 30px;',
  'color: blue; font-size: 20px;'
);
27

Passing %c in the middle of the string will apply styles to text after this directive:

console.log('not applied %c applied', 'color: red; font-size: 30px;');
28

Examining memory usage with memory in Chrome

In Google Chrome you can use memory to examinine current heap size status.

console.memory;
29

It is equivalent to window.performance.memory object.

Checking assertions with assert

The assert method writes an error message to the console if the assertion is false.

console.assert(assertion, message);
30

Clearing console output using clear

clear allows to clear the console if the environment allows it.

clear();