Home > Software engineering >  Why is adding objects to an array in a loop adds the same object many times?
Why is adding objects to an array in a loop adds the same object many times?

Time:09-19

I'm building a sort of a calendar app in ExpressJS and TypeScript and i have this function that handles events that happen periodically, before sending a response with an array of events for a requested month.

let response: TEventResponse[] = [];
    for (let i = 0; i < events.length; i  ) {
        let e = events[i];
        if (!e.isPeriodical) {
            const event: TEventResponse = {
                beginning: e.beginTime,
                ending: e.endTime,
                title: e.title,
                description: e.description,
                place: e.place,
            };
            response.push(event);
        } else {
            let beginning = new Date(e.beginTime);
            const upperDate = new Date();
            upperDate.setFullYear(year);
            upperDate.setMonth(month   1);
            upperDate.setDate(1);
            const lowerDate = new Date();
            lowerDate.setFullYear(year);
            lowerDate.setMonth(month);
            lowerDate.setDate(1);
            console.log(lowerDate);
            console.log(upperDate);

            let dateBoundary = undefined;
            if (e.dateBoundary) {
                dateBoundary = e.dateBoundary;
            } else {
                dateBoundary = upperDate;
            }
            console.log(dateBoundary);

            if (dateBoundary >= upperDate) {
                const periodicalEventsArr: TEventResponse[] = [];
                while (beginning <= dateBoundary && beginning < upperDate) {
                    if (beginning >= lowerDate) {
                        const event: TEventResponse = {
                            beginning: beginning,
                            ending: e.endTime,
                            title: e.title,
                            description: e.description,
                            place: e.place,
                        };

                        periodicalEventsArr.push(event);
                        console.log(periodicalEventsArr);
                    }
                    const n = e.repeatPeriod!;
                    switch (e.repeatPeriodUnit) {
                        case "DAY":
                            beginning.setDate(beginning.getDate()   n);
                            break;
                        case "WEEK":
                            beginning.setDate(beginning.getDate()   n * 7);
                            break;
                        case "MONTH":
                            beginning.setMonth(beginning.getMonth()   n);
                            break;
                        case "YEAR":
                            beginning.setFullYear(beginning.getFullYear()   n);
                            break;
                    }
                    console.log(periodicalEventsArr);
                }
                response.concat(periodicalEventsArr);
            }
        }
    }

    return response;

The outer for loop works as it is supposed to but the inner while loop which is supposed to take a periodical event and add it to the array certain amount of times behaves strangely.

It is meant to add the same event many times but change the date each time by a given period of days. It seems to add the event correctly (as the first console.log(periodicalEventsArr) shows) but when the date is then updated it changes the value of the 'beginning' field of the event already in the array (as seen with the second console.log(periodicalEventsArr)). On the next iteration an event with the updated date is again appended correctly but then after updating the date it changes not only the 'beginning' value of the newly added event but also that value of all the previously added events.

At the end of the loop I'm left with an array in which all the elements are the one that should have been added as the last one.

I have thought about this for quite a while now and I still have no idea what is going on. I would appreciate any insight into what I'm doing wrong.

CodePudding user response:

The problem is that you always add the same object, beginning and at each case you change its state, which ruins the earlier array items. Let's reproduce the problem in simple terms:

let beginning = new Date(); //a new Date
let myArray = []; //a new array
myArray.push(beginning);//let's add this date to the array
console.log(myArray);//and viola! It shows the current day
beginning.setFullYear(2001);//let's go back to the past with the date object
console.log(myArray);//and the already added array item changed

So, what should we do instead:

    let beginning = new Date(); //a new Date
    let myArray = []; //a new array
    myArray.push(beginning);//let's add this date to the array
    console.log(myArray);//and viola! It shows the current day
    beginning = (new Date(beginning)).setFullYear(2001);//let's go back to the past with the date object
    console.log(myArray);//and the array item is unchanged

So, how to apply this in your case:

                        const event: TEventResponse = {
                            beginning: new Date(beginning), //we "clone" the date instead of passing the exact same object
                            ending: e.endTime,
                            title: e.title,
                            description: e.description,
                            place: e.place,
                        };
  • Related