Code Buckets

Buckets of code

Node

Reliable console.log output for JavaScript ES6 Map and Set

looking for content after console.log of ES6 set
Console.log an ES6 Set. Where have the contents gone?

Problem

Here’s something that has tripped me up a few times now – when you console.log out the contents of a Set or Map in ES6 the it looks empty which isn’t true.

Example

const set = new Set(['sun', 'sea', 'surf']);
console.log(`Set output ${JSON.stringify(set)}`);

Output

Set output {}

The console tells me it is empty and it’s not. This is the same with Maps. This contrasts with Arrays and objects which show the content if logged out using this code. 

If you are using console.log to quickly debug then this is a pain. I often wrap the output in template literals to add context and it’s that string conversion that hides the content. It turns out that objects, arrays, maps, sets and objects all behave slightly differently when logging to the console. So in detail …

Console.log for ….

All examples have been run through Node.js. The same holds true if running through a browser i.e. with React or Angular.

Array

Example

const array = ['sun', 'sea', 'surf'];

console.log(array);
console.log(`array ${array}`);
console.log(`array ${JSON.stringify(array)}`);

Output

[ 'sun', 'sea', 'surf' ]
array sun,sea,surf
array ["sun","sea","surf"]

The array plays most nicely with console.log. It displays it’s contents in all circumstances

Object

Example

const object = { sun: 1, sea: 2, surf: 3 };

console.log(object);
console.log(`array ${object}`);
console.log(`array ${JSON.stringify(object)}`);

Output

{ sun: 1, sea: 2, surf: 3 }
object [object Object]
object {“sun":1,"sea":2,"surf":3}

Objects will only display correctly in a template literal if the JSON is stringified first. This is why I habitually use JSON.stringify when logging to the console. 

ES6 Set

Example

const set = new Set(['sun', 'sea', 'surf']);

console.log(set);
console.log(`set ${set}`);
console.log(`set ${JSON.stringify(set)}`);

Output

Set(3) { 'sun', 'sea', 'surf' }
set [object Set]
set {}

As with arrays and objects, logging the object directly works nicely but wrapping in a template literal hides the content i.e. when it is coerced to a string. The trick of JSON.stringifying the set doesn’t help now.

ES6 Map

Example

const map = new Map([[1, 'sun'], [2, 'sea'], [3, 'surf']]);

console.log(map);
console.log(`map ${map}`);
console.log(`map ${JSON.stringify(map)}`);

Output

Map(3) { 1 => 'sun', 2 => 'sea', 3 => 'surf' }
map [object Map]
map {}

As with the Set, Map only logs directly, not when combined in a template literal

Overall

  • Logging directly always works
  • Arrays can be logged in a template literal
  • Objects can be logged in a template literal if the JSON is stringified first
  • Sets and Maps don’t log with template literals – they appear empty

Solution

The solution is to convert Sets and Maps to arrays before logging out. The following code checks the type and applies the correct logging rule

const objectPrintFormatter = (toPrint) => {

    if(toPrint instanceof Set || toPrint instanceof Map) {
        return JSON.stringify(Array.from(toPrint));
    }
    else if(toPrint instanceof Object) {
        return JSON.stringify(toPrint);
    }
    return toPrint;
} 

const array = ['sun', 'sea', 'surf'];
const set = new Set(['sun', 'sea', 'surf']);
const map = new Map([[1, 'sun'], [2, 'sea'], [3, 'surf']]);
const object = { sun: 1, sea: 2, surf: 3 };

console.log(`array ${objectPrintFormatter(array)}`);
console.log(`set ${objectPrintFormatter(set)}`);
console.log(`map ${objectPrintFormatter(map)}`);
console.log(`object ${objectPrintFormatter(object)}`);

Output

array ["sun","sea","surf"]
set ["sun","sea","surf"]
map [[1,"sun"],[2,"sea"],[3,"surf"]]
object {"sun":1,"sea":2,"surf":3}

Now each type logs its contents to the console rather than appearing empty. The key thing to remember is that if ES6 Sets and Maps appear empty, they may not be. It could just be the way they are being logged out to the console.

Code

As ever, the code is on my GitHub site here

https://github.com/timbrownls20/Demo/tree/master/Node/es6-console-log

Useful Links

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
Map and Set official documentation fromt the ES6 standard.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
JSON.stringify documentation

https://codebuckets.com/2018/06/17/extending-typescript-to-serialise-map-objects-to-json/
I’ve an additional post about extending the ES6 Map Typescript definition to include a toJSON which also solves this issue of ES6 types not displaying their content in the console. Embarrasingly, I forgot that I’d written this post a few years ago on the same topic. I think this latest post adds some additional context by comparing the functionality across several different objects, so I’ll leave both in.

LEAVE A RESPONSE

Your email address will not be published. Required fields are marked *