Search code examples
javascriptarraysjavascript-objectsconsole.log

JAVASCRIPT: Console.log() does not print the value of arrays (with objects) correctly. Instead, it prints a summary


I have this simple javascript app.

let array = [{ fruit: "banana" }];
console.log(array);
array.push({ fruit: "apple" });
console.log(array);

I expect the first console.log() to print an array with one object. I also expect the second console.log() to print an array with two objects. And this is what gets printed in CHROME console.

[{…}]
(2)[{…}, {…}]

So everything seems to be all right. The first array seems to contain one object and the second array seems to contain two objects. But when I inspect the array in the console, this what I see.

[{…}]
  0: {fruit: 'banana'}
  1: {fruit: 'apple'}
  length: 2
  [[Prototype]]: Array(0)

(2)[{…}, {…}]
   0: {fruit: 'banana'}
   1: {fruit: 'apple'}
   length: 2
   [[Prototype]]: Array(0)

This is a very unexpected behavior, because the first object seems to contain two objects.

CHATGPT explained that this is a standard behavior. In addition to that, it admits that "console displaying summaries instead of the full content can indeed be confusing at times"

The problem is that it makes debugging more difficult. It is not so easy to keep track of the values in my app. To see the content of the arrays, CHATGPT suggests to use JSON.stringify() method. Like this.

let array = [{ fruit: "banana" }];
console.log(JSON.stringify(array));
array.push({ fruit: "apple" });
console.log(JSON.stringify(array));

And it works, it gives me this result in the console.

[{"fruit":"banana"}]
[{"fruit":"banana"},{"fruit":"apple"}]

The problem with this method is that it works quite well with arrays that contain just a few simple objects. But it may be really difficult to read if there are many complex objects in the array.

So my question is. Apart from using the JSON.stringify() method, is there any other technique to make the arrays more readable?


Solution

  • The console keeps references to objects you log into it (not copies). So when you expand an object in the console the current state of the object is displayed. Since you pushed a new element into the array before you expand the array you will have this new element added to the expanded array.

    To change that you should log your object fully as text or make a copy of an object/array.

    There are several methods to freeze the objects in the console.

    One way would be to create a deep copy with structuredClone() to make a "current snapshot" of an object (you can create a deep copy also with JSON.parse(JSON.stringify(obj))).

    That gives you exact the console's UX as with an original object (in our case an array):

    let array = [{ fruit: "banana" }];
    console.log(structuredClone(array));
    array.push({ fruit: "apple" });
    console.log(structuredClone(array));

    A shallow copy (shorter syntax) could be done with arr.slice() or spread [...arr]:

    let array = [{ fruit: "banana" }];
    console.log(array.slice());
    array.push({ fruit: "apple" });
    console.log(array.slice());

    You could use JSON.stringify(obj, null, 4) (where 4 means number of spaces to indent the JSON) to log in a readable form similar to the console expanded version:

    let array = [{ fruit: "banana" }];
    console.log(JSON.stringify(array, null, 4));
    array.push({ fruit: "apple" });
    console.log(JSON.stringify(array, null, 4));

    Also note that console.log takes multiple arguments so you could output arrays with the spread syntax too, thus at least displaying different item count:

    let array = [{ fruit: "banana" }];
    console.log(...array);
    array.push({ fruit: "apple" });
    console.log(...array);

    A combination of the both methods is possible, here we want a compact format and use Array::map() to stringify array items in a compact JSON form:

    let array = [{ fruit: "banana" }];
    console.log(...array.map(JSON.stringify));
    array.push({ fruit: "apple" });
    console.log(...array.map(JSON.stringify));