Redeclared variables taking values of old array

Viewed 37

I have two arrays organHolidayYears, which contains years (with a start date and end date), and sortedHolidayWorkingPatterns, which contains the days worked regularly by a staff member and when they started and finished using that shift pattern. I'm trying to attach the working patterns to the year's array and also, the bit which is proving difficult, truncate the start date/end date of the working pattern to match the year they're being attached to.

For example, if a staff member has a particular shift pattern from July 2021 to June 2022. Then this shift pattern will be attached to 2021 with start date July 2021 and end date December 2021. This shift pattern will also be attached to 2022 with start date Jan 2022 and end date June 2022.

I've created a for loop that cycles through the years and through the working patterns, attaching them to years as necessary. However, the truncated start/end dates are being overwritten. In the above example, I end up with, for both 2021 and 2022, the start dates being Jan 2022 and the end date being December 2021. I redeclare the variable in each loop of the for loop (using workingPatternsTemp) but the declared variable workingPatternsTemp is taking the properties of workingPatternsTemp in the old loop. Why is this happening and how can I stop it? Thanks!

  for (let j = 0; j < organHolidayYears.length; j++) { //cycle through holiday years and attach working patterns
    var holidayYear = organHolidayYears[j];
    for (let i = 0; i < sortedUserWorkingPatterns.length; i++) { // cycle through working patterns and attach to given year if necessary
      var workingPatternsTemp = sortedUserWorkingPatterns[i];
      var toDate = holidayYear.unixEndDate; //holiday year end date
      var fromDate = holidayYear.unixStartDate; //holiday year start date
      var workingPatternStartDate = workingPatternsTemp.unixStartDate;
      var workingPatternEndDate = workingPatternsTemp.unixEndDate;
        // CASE 1: PATTERN STARTS DURING YEAR
        if (workingPatternStartDate <= toDate && workingPatternStartDate >= fromDate) {
          // CASE 1a: PATTERN ENDS DURING YEAR
          if (workingPatternEndDate <= toDate) {
            holidayYear.workingPatterns.push(workingPatternsTemp); // add working pattern to holiday year
          }
          // CASE 1b: PATTERN ENDS AFTER YEAR
          else  {
            workingPatternsTemp.unixEndDateInHolidayYear = toDate; // truncate working pattern at end of year
            holidayYear.workingPatterns.push(workingPatternsTemp); // add working pattern to holiday year
          }
        // CASE 2: PATTERN ENDS DURING YEAR (BUT DOES NOT START DURING YEAR) 
        } else if (workingPatternEndDate <= toDate && workingPatternEndDate >= fromDate) {
            workingPatternsTemp.unixStartDateInHolidayYear = fromDate; // truncate working pattern at start of holiday year
            holidayYear.workingPatterns.push(workingPatternsTemp); // add working pattern to holiday year
        }
        // CASE 3: PATTERN DOES NOT OVERLAP YEAR
        else {}
    }
  }

1 Answers
var workingPatternsTemp = sortedUserWorkingPatterns[i];
workingPatternsTemp.unixEndDateInHolidayYear = toDate;

It is a little difficult to know 100% for sure without seeing some real data flowing through your code, but I'm about 99.9% sure I know your problem. These lines above illustrate it. workingPatternsTemp is a temporary variable declared inside the scope of your inner for loop; however, it is a reference to an object in a scope outside your for loop. When you create workingPatternsTemp, it is not copying the object, but rather pointing to the existing object. So when you modify its properties, you are modifying the properties of the original object.

holidayYear.workingPatterns.push(workingPatternsTemp);

Pushing that temporary var into an array also pushes a reference to that same object--even on future iterations of your for loop, when you declare workingPatternsTemp and modify it, it will be modifying the object stored at the reference you previously pushed.

Here's an example:

let arr = [
  {a: 1},
  {a: 2},
  {a: 3}
];

for(let i = 0; i < arr.length; i++)
{
  let temp = arr[i];
  temp.a = 5;
}

console.log(arr);

I modified only the variable temp which I defined inside the for loop, but the original objects inside arr are still modified after the loop finishes.

To get around this, you can create a copy of your object when you declare workingPatternsTemp. One of the simplest ways to do that is with the spread operator (...).

Here's that same code, modified to copy with the spread operator:

let arr = [
  {a: 1},
  {a: 2},
  {a: 3}
];

for(let i = 0; i < arr.length; i++)
{
  let temp = {...arr[i]};
  temp.a = 5;
}

console.log(arr);

You'll see the original array is no longer modified after the loop exits. Here's how you'd do that in your code:

var workingPatternsTemp = {...sortedUserWorkingPatterns[i]};

Also note: if your object contains nested objects, those will have to be copied too. The spread operator on just the outer object would copy the reference to those objects. It is not a true deep copy.

Related