1

I have just noticed some strange behavior in one of my Arrays. I am sure the issue is with how Javascript stores object references in arrays. I will demonstrate the issue with a bit of code I posted as an answer to another question on SO. The code, just loops to get todays date and the 6 previous dates of the month, pretty self explanatory.

var dates = [];
var date = new Date();

for (var i = 0; i < 7; i++){
  var tempDate = new Date();
  tempDate.setDate(date.getDate()-i);
  dates.push(tempDate);  
}
console.log(dates);

Output: [Thu Jun 05 2014 14:54:14 GMT+0100 (GMT Daylight Time), Wed Jun 04 2014 14:54:14 GMT+0100 (GMT Daylight Time), Tue Jun 03 2014 14:54:14 GMT+0100 (GMT Daylight Time), Mon Jun 02 2014 14:54:14 GMT+0100 (GMT Daylight Time), Sun Jun 01 2014 14:54:14 GMT+0100 (GMT Daylight Time), Sat May 31 2014 14:54:14 GMT+0100 (GMT Daylight Time), Fri May 30 2014 14:54:14 GMT+0100 (GMT Daylight Time)]

This is correct, and is expected, as tempDate is continually recreated as a new Date object inside of the loop.

When I take tempDate out of the loop however, it seems to update all of the objects in the array every iteration of the loop (also the loop seems to go one Month and 1 day too far to 29th apr):

var dates = [];
var date = new Date();
var tempDate = new Date();

for (var i = 0; i < 7; i++){
  tempDate.setDate(date.getDate()-i);
  dates.push(tempDate);  
}
console.log(dates);

Output: [Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time), Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time), Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time), Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time), Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time), Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time), Tue Apr 29 2014 14:52:21 GMT+0100 (GMT Daylight Time)]

So the two questions I pose are:

  1. Why does the object stored in the array keep mutating with every iteration? (I suspect this is because of the way Javascript is storing the references to the object, but an explanation would be nice)
  2. Why does the loop run one too far in the second bit of code? The first example shows the loop ends after 7 successful iterations, on May the 30th (7 days in the past), the second example shows the resultant date after the iterations as the 29th april - more than a month into the past. Why?

edit: I have a rudimentary jsfiddle, to allow testing the code.

Husman
  • 6,819
  • 9
  • 29
  • 47
  • 4
    This is how most languages behave... the first code creates a new date object in each iteration, the second code only creates 1 (one) date object and then updates its value in each iteration. The array simply contains the same date object multiple times. – Bart Jun 05 '14 at 14:14
  • Yup, thought so. That answers question 1. Now (considering that I havent modified the loop conditions, why is the loop seemingly ending up 8 days in the past in the second example, compared to 7 in the first example? – Husman Jun 05 '14 at 14:16
  • I'm... confused now. It's not just ending 8 days in the past, it's ending a whole month in the past. I mean... I'm not sure wtf just happened here. – Bart Jun 05 '14 at 14:27
  • Its not a month in the past. Its the 5th of May today, its ending up 7 days in the past in the first example (so 30th of April) - which is correct. And in the second example its ending up 8 days in the past, 29th April. In any case it will end up in April, as we are on the 5th day of this month, and subtracting 7 days. – Husman Jun 05 '14 at 14:30
  • Last time I checked it's the 5th of June... There's a month between june and april. But anyway, I got why this happens: Date#setDate only sets the day of the month. So at the last iteration, the month of tempDate is moved to May, and then you call setDate(-1), which reduces the month and sets the date again. – Bart Jun 05 '14 at 14:32
  • ah, your right, im looking at 2 different sets of code. It is 5th of June today, so that month jump is even more perplexing. – Husman Jun 05 '14 at 14:34
  • @Bart modified the question a bit – Husman Jun 05 '14 at 14:35
  • Peter's answer explains why this happens. when date.setDate() is called with number <= 0, the month of that date is reduced. This happens at iteration 6: June 0 == May 31. At this point, the month of tempDate is "May". In iteration 7 you setDate(-1) which once again reduces the month of tempDate, this time from May to April. – Bart Jun 05 '14 at 14:44

1 Answers1

4

var tempDate = new Date(); creates new object. so in this example:

var array = [tempDate,tempDate,tempDate,tempDate,tempDate];

array[0] is same object as array[1]

this is just how objects works in almost every programming language:

var a = tempDate;
var b = tempDate;
var c = b;

(in above example a, b, c, and tempDate is same thing)


Regarding question 2:

please have a look at this fiddle http://jsfiddle.net/Mqnmm/

with new object tempDate is always today, then you apply setDate()

with old object, before last literation date is Sat, 31 May 2014 14:23:34 GMT, then you apply tempDate.setDate(-1) which sets date to last N days of previous month

Subtract days from a date in JavaScript please check Rob Dawley`s answer to properly adjust dates

Community
  • 1
  • 1
Peter
  • 16,453
  • 8
  • 51
  • 77
  • Yup, thought so. That answers question 1. Now (considering that I havent modified the loop conditions) why is the loop seemingly ending up 8 days in the past in the second example, compared to 7 days in the first example? – Husman Jun 05 '14 at 14:17