125

This code:

foo = [{id: 1},{id: 2},{id: 3},{id: 4}, {id: 5}, ];
console.log('foo1', foo, foo.length);
foo.splice(2, 1);
console.log('foo2', foo, foo.length);

Produces the following output in Chrome:

foo1 
[Object, Object, Object, Object, Object]  5
    0: Object
    1: Object
    2: Object
    3: Object
    length: 4
    __proto__: Array[0]
     5 (index):23
foo2 
[Object, Object, Object, Object]  4
    0: Object
    1: Object
    2: Object
    3: Object
    length: 4
    __proto__: Array[0]

Fiddle: http://jsfiddle.net/2kpnV/

Why is that?

Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
dan-klasson
  • 13,734
  • 14
  • 63
  • 101
  • See also [console.log() async or sync?](https://stackoverflow.com/q/23392111/1048572) – Bergi Feb 14 '20 at 21:30
  • 1
    @Bergi Would you have a strong objection to switching the linked question to be a duplicate of this one, rather than the other way around? I think the top answer here is notably better. (concise, recommends method which will properly log deep object structure.) Answer-votes per question-vote and per visitor also seem to agree. I'd be happy to talk on Meta for longer discussion and input from others if needed – CertainPerformance Feb 23 '20 at 07:30
  • @CertainPerformance The current canonical is older, has a better title, and better question text (with simple example and including screenshot). I agree that the accepted answer here gives a better explanation and a solution (although not a solution for arrays, which these questions are about). How would you feel about getting the questions merged? – Bergi Feb 23 '20 at 16:03
  • @Bergi No, do not merge it. The title of the question is not great, but it's precisely the title that brings users to this question. The link to the other duplicated question is fine. – dan-klasson Feb 23 '20 at 19:07

2 Answers2

190

Examining objects via console.log happens in an asynchronous manner. The console receives a reference to the object synchronously, but does not display the properties of the object until it is expanded (in some cases, depending on the browser and whether you have dev tools open when the log happens). If the object has been modified before examining it in the console, the data shown will have the updated values.

For example, Chrome will show a little i in a box which, when hovered, says:

Object value at left was snapshotted when logged, value below was evaluated just now.

to let you know what you're looking at.

One trick for logging in these cases is to log the individual values:

console.log(obj.foo, obj.bar, obj.baz);

Or JSON encode the object reference:

console.log(JSON.stringify(obj));
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • 25
    As stated in another answer, `JSON.parse(JSON.stringify(obj))` may be much better to see the log as a json object instead of a string – Yasin Okumuş Apr 07 '17 at 12:51
  • 4
    or: console.log( Object.assign({}, obj) ); - this will create a new copy of object. – cimak Jul 21 '17 at 11:59
  • 1
    I personally prefer the following for readability ‘console.log(JSON.stringify(obj, null, '\t'))’ – Joey Oct 30 '17 at 15:33
  • I still have cases where conole.log(obj) will truncate the object log down to one line and an ellipsis. Even when I've copied the object, stringified, and parsed. – paiego Dec 20 '17 at 20:12
  • 12
    What is the reasoning behind Chrome doing this instead of showing the value as it was at the time of logging? Wouldn't that be more useful? – ESR May 31 '18 at 04:53
  • 3
    @cimak, for some reason I am still getting an object that shows the last values of it's properties when using `console.log(Object.assign({}, obj))`. Using `console.log( JSON.parse(JSON.stringify(obj)) )` does show the values at the time of output. – Peter Oct 03 '18 at 14:03
  • 4
    @Peter - i was partly wrong, `Object.assign` will work only for object that contain primitive values only (because `Object.assign` makes shallow copy, not deep copy). If `obj` contain another object, then value of that nested object will be "evaluated" separately. – cimak Oct 03 '18 at 16:50
  • I'm puzzled about why it is implemented this way... is there a use case in which this behavior is desirable? (i.e. if I use console.log to display an object *before* I modify the object, when would I want the object displayed in the console output to reflect its state *after* modification?) Or is it just that the console is trying to be lazy and save memory by not snapshotting objects at the time they are logged? – dinosaur Sep 12 '19 at 22:26
1

Redefining console.log will solve the problem.

var originalLog = console.log;
console.log = function(obj) {
    originalLog(JSON.parse(JSON.stringify(obj)));
};
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
Latpaw
  • 121
  • 1
  • 4
  • 15
    It's not so useful because in console it will display the number of line where this function is defined instead of actual line where I call console.log – Avael Kross Sep 04 '17 at 10:28