1

I have following code to get list of object with new timestamp. I am using momemt lib to update time. Basic logic is to loop N times and collect list of times adding 1 min to each.

var moment = require('moment');
var _ = require('lodash');
var startDate = moment("1995-12-25");

var currentDate = startDate;

var result = _.range(5).map(function () {
  const nextTimestamp = currentDate.add(60, 's');
  console.log('nextTimestamp: ' + JSON.stringify(nextTimestamp));
  currentDate = nextTimestamp;

  return {
    timestamp: nextTimestamp
  }
});

console.log('result: ' + JSON.stringify(result, null, 2));

I am expecting it will give a array on timestamp with 1 min difference. The output I am seeing is:

nextTimestamp: "1995-12-25T06:01:00.000Z"
nextTimestamp: "1995-12-25T06:02:00.000Z"
nextTimestamp: "1995-12-25T06:03:00.000Z"
nextTimestamp: "1995-12-25T06:04:00.000Z"
nextTimestamp: "1995-12-25T06:05:00.000Z"
result: [
  {
    "timestamp": "1995-12-25T06:05:00.000Z"
  },
  {
    "timestamp": "1995-12-25T06:05:00.000Z"
  },
  {
    "timestamp": "1995-12-25T06:05:00.000Z"
  },
  {
    "timestamp": "1995-12-25T06:05:00.000Z"
  },
  {
    "timestamp": "1995-12-25T06:05:00.000Z"
  }
]

Can anyone help me understand why array is coming with last timestamp for all array element.

Thanks.

Raymond Chen
  • 44,448
  • 11
  • 96
  • 135
αƞjiβ
  • 3,056
  • 14
  • 58
  • 95
  • 1
    because the callback function is returning a reference to an object `nextTimestamp ` rather than a copy of the object. See [this question](https://stackoverflow.com/questions/518000/is-javascript-a-pass-by-reference-or-pass-by-value-language) – Stephen Thomas Jul 11 '19 at 15:20

3 Answers3

4

This happens because you work with one currentDate object, which you keep mutating. Even when you have put that object in the array, it does not stop from getting mutated by what you do in the next iteration.

You need to create separate objects, and for this you can use the clone method available in momentjs:

currentDate = nextTimestamp.clone();

Or alternatively, call moment():

currentDate = moment(nextTimestamp);
trincot
  • 317,000
  • 35
  • 244
  • 286
3

Your problem has nothing to do with map.

See the documentation for moment:

It should be noted that moments are mutable. Calling any of the manipulation methods will change the original moment.

Each entry in the array is a reference to the same moment, which you just modify the value of repeatedly.

You need to use a new moment object (you can get one by clone()ing the old one) each time you add the time to it:

var startDate = moment("1995-12-25");
var nextTimestamp = startDate;

var result = _.range(5).map(function () {
  nextTimestamp = nextTimestamp.clone().add(60, 's');
  console.log('nextTimestamp: ' + JSON.stringify(nextTimestamp));
  return {
    timestamp: nextTimestamp
  }
});
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
0

The Array.map function returns a new array with the results being equal to the given function being applied to every element in the array. Also you are not getting any of the elements to change them. Map takes in a parameter for the current element that needs to be changed.

 //I didn't use lodash but the theory is the same 
 var range = [0, 1, 2, 3, 4, 5];  
 var result = range.map(function (element) {
    return element += 1;
 });

 console.log(result); //1, 2, 3, 4, 5, 6
Cyberboy1551
  • 345
  • 1
  • 13