2

i am facing a strange behaviour in a for loop that contains array of objects

The following is the example

var store = {};
var storesWithTimestamps = [];

for (var i=0;i<2;i++){                      
    console.log("inital list",storesWithTimestamps); //1
    console.log("inital length",storesWithTimestamps.length); //2

    store = {};
    store.latestTimestamp = null;
    store.storeName = "testStore";
    storesWithTimestamps.push(store);

    console.log("new list",storesWithTimestamps); //3
    console.log('new length',storesWithTimestamps.length); //4
}

The problem is log statement 3 shows a array of object with 2 items in the 1st iteration , but the log statement 4 shows the length as 1.

The output of the log statement 3 is the same for both the iteration like this, [{latestTimestamp:null,storeName:"testStore"},{latestTimestamp:null,storeName:"testStore"}]

Where as it should be 1st loop:

[{latestTimestamp:null,storeName:"testStore"}]

2nd loop:

[{latestTimestamp:null,storeName:"testStore"},{latestTimestamp:null,storeName:"testStore"}]

FYI: this works as expected in Safari but not on chrome - OSX Attached fiddle: http://jsfiddle.net/gauravsoni/09Ls3rtx/

Attached screenshot: wrong length

Gaurav_soni
  • 6,064
  • 8
  • 32
  • 49
  • 1
    http://jsfiddle.net/arunpjohny/fysnjt74/1/ ? looks fine – Arun P Johny Oct 05 '15 at 08:20
  • 1
    Working fine in Chrome for me. – Spencer Wieczorek Oct 05 '15 at 08:20
  • @SpencerWieczorek pls see screenshot, no idea whats happening... – Gaurav_soni Oct 05 '15 at 08:23
  • 1
    The cose is fine, and it works on Chrome. I'm voting for closing because I cannot reproduce the problem. – JotaBe Oct 05 '15 at 08:23
  • @JotaBe pls see the screen shot, its a valid issue. – Gaurav_soni Oct 05 '15 at 08:24
  • 1
    I actually can see it in the console in js fiddle. But only the first time it runs. The array already has 2 elements – sirrocco Oct 05 '15 at 08:24
  • @sirrocco yea thats what i am also wondering that how the values are already in the array in the 1st iteration ... Initial list items in the 1st iteration should be [] – Gaurav_soni Oct 05 '15 at 08:26
  • @Gaurav_soni Which is your Chrome version? Have you tried fully restarting it (closing Chrome with the menu, and opening it again)? – JotaBe Oct 05 '15 at 08:26
  • 1
    I have Version 45.0.2454.101 m and is reproducible, I don't see it in Chrome Canary – sirrocco Oct 05 '15 at 08:29
  • I'm on 45.0.2454.101 (64-bit) OS X , let me try on cannary – Gaurav_soni Oct 05 '15 at 08:30
  • 2
    It is due to javascript points objects by reference, so changing the object leads to change it in console. Try to place debugger in the loop and see how your output will change step by step. – yorlin Oct 05 '15 at 08:30
  • Same version here, on Windows 8 x64.It must be a bug on the OS X version. – JotaBe Oct 05 '15 at 08:32
  • @yorlin, Its not giving the same output all the time. If it is a known behavior of `js` then it should give same output everytime.. – Rayon Oct 05 '15 at 08:32
  • @yorlin, the console captures the state of the object when it's logged. It doesn't use references to the current object. The console has always worked like this. – JotaBe Oct 05 '15 at 08:34
  • @JotaBe but shouldn't this be the same in firefox and safari also if its some referencing issue ? – Gaurav_soni Oct 05 '15 at 08:37
  • @Gaurav_soni I think you didn't understand my comment. It was an answer to yorlin's comment, which said it should be a reference problem. And I'm telling him that's not the case. You misread it ;) – JotaBe Oct 05 '15 at 08:47

3 Answers3

2

Actually it's due to the Debugger behavior.

If the debugger is opened when you run the script, the output in the console will be correct.

If the debugger is not opened when you run the script, the object is evaluated at the time the console is displayed. That's why you can see 2 objects in the array.

I think it is what @yorlin was meaning.

Addendum: You may want to use the JSON.stringify() method to log the instant object properties:

console.log( "inital list:", JSON.stringify( storesWithTimestamps ) ) //1
...
console.log( "new list:", JSON.stringify( storesWithTimestamps ) ) //3

Nota bene: In the console, italic values were evaluated instantly, while non-italic values are evaluated when they are displayed (as you can see in the blue [ i ] next to the values).

Conclusion: In the second posted screenshot we can see clearly it was not a Chrome bug.

Supersharp
  • 29,002
  • 9
  • 92
  • 134
  • In my case i have the debugger opened and running the script, its the same no matter what. – Gaurav_soni Oct 05 '15 at 08:40
  • @Gaurav_soni, are you sure you cleared the log window before reloading the page? Maybe there's a problem with your browser because noone seems able to reproduce the behavior with console opened. I tested it on Chrome 46 and Firefox with the expected result. – Supersharp Oct 05 '15 at 08:59
  • Yes, tried with the console opened/closed , restarted the browser. Same code works fine in safari and firefox. Should be a browser issue on OSX , @sirrocco also seems to be facing the same issue. – Gaurav_soni Oct 05 '15 at 09:01
  • Are you on windows or mac ? – Gaurav_soni Oct 05 '15 at 09:01
  • I tried it on a windows machine also, same issue there too. With the console opened the new list log shows both the values during the 1st iteration. – Gaurav_soni Oct 05 '15 at 09:12
  • I've installed Chrome 45.0.2454.101 on Windows 7, and I get the expected bahavior (no issue as with version 46 and Canary). With what Chrome version do you get the issue on Windows? – Supersharp Oct 05 '15 at 09:32
  • The chrome version on windows 7 is 45.0.2454.101 m, weird issue... should i post a screen shot of windows machine ? – Gaurav_soni Oct 05 '15 at 09:35
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91373/discussion-between-supersharp-and-gaurav-soni). – Supersharp Oct 05 '15 at 09:44
1

I've tried this....Just like @yorlin and @Supersharp said.

You can check it in console more clear.

var store = {};
var storesWithTimestamps = [];

//Checkout the status of ary
function displayObj(objAry){
    var info="\n";
    for(var i=0;i<objAry.length;i++){
        var data=objAry[i];
        info+='\t\trecord('+i+').id:'+data.id+'\n';
    }
    return info;
}

for (var i=0;i<2;i++){                      
    console.log("inital list",storesWithTimestamps); //1
    console.log("inital length",storesWithTimestamps.length); //2

    //put an id to identify
    store = {id:i};
    store.latestTimestamp = null;
    store.storeName = "testStore";
    storesWithTimestamps.push(store);

    console.log("new list",displayObj(storesWithTimestamps)); //3
    console.log('new length',storesWithTimestamps.length); //4
}
Lin Yuan
  • 528
  • 2
  • 12
1

This is happening due to async nature of console.log() you can find more details regarding this behavior at console.log() async or sync?

you can try workaround to log the proper value as below -

var store = {};
var storesWithTimestamps = [];

for (var i=0;i<2;i++){                      
    console.log("inital list",storesWithTimestamps); //1
    console.log("inital length",storesWithTimestamps.length); //2

    store = {};
    store.latestTimestamp = null;
    store.storeName = "testStore";
    storesWithTimestamps.push(store);

    console.log("new list",JSON.stringify(storesWithTimestamps)); //3 instead of passing object, pass serialized snapshot of the object
    console.log('new length',storesWithTimestamps.length); //4
}
Community
  • 1
  • 1
Manoj Shevate
  • 742
  • 4
  • 18