2

UPDATE: I now understand that in the code below I am mutating the aggregateData array as I iterate through pagedData.

  1. I'd like to know how I could do this without mutation?
  2. And in general how much concern there might be when mutating a locally defined array (like I did in my example) when trying to respect immutability as much as possible in a codebase? Since the array is defined locally I wonder how mutating the array could really have any negative impact?
const pagedData = [
  {data: ["val1", "val2"], nextPage: 2},
  {data: ["val3", "val4"], nextPage: 3},
  {data: ["val5", "val6"]}
];

const aggregator = () => {
  let aggregateData = [];
  let hasNextPage;
  let page = 1;

  do {
    const { data, nextPage } = pagedData[page - 1];
    aggregateData = [...aggregateData, ...data];
    page = nextPage;
    hasNextPage = nextPage;
  } while (hasNextPage);

  return aggregateData;
}

console.log(aggregator());

/* output: ["val1", "val2", "val3", "val4", "val5", "val6"] */

1 Answer 1

2

Immutability helps reduce hard to catch bugs sometimes, but that may not always be required or be the ideal case.

What is Immutability ?

Not changing the value refers to immutability. In Javascript, array and objects are mutable.

Examples of immutability:

let arr = ['John', 'Alice'];

// Adding element is mutating
arr.push('Oliver');

// Updating data is mutating
arr[1] = 'Lily'

Lot of other functions can mutate this array. More here

  • copyWithin
  • fill
  • pop
  • push
  • reverse
  • shift
  • sort
  • splice
  • unshift

Also, note that defining an array or object as a const does not guarantee immutability. For example:

const obj = {
  name: 'foo'
}
// update name
obj.name = 'bar';

console.log(obj);

const arr = ['foo'];

// push new item
arr.push('bar');

console.log(arr);

Now to answer your question. when can spread operator mutate and when does is not ?

If we have this array, whenever any data in this array mutates, then it loses immutability.

let arr = ['Obito', 'Sasuke'];
let sameReferenceArray = arr;

console.log(arr === sameReferenceArray);

// here the original array did not mutate 
let newArray = [...arr, 'Madara'];
console.log(arr === sameReferenceArray);

// but here it did mutate as the new array is assigned back to arr
arr = [...arr, 'Madara'];
console.log(arr === sameReferenceArray);

There are more examples of what methods mutate and what don't and you'll learn them over time.

Edit How Mutation can have negative impact ?

// simple example demostrating negative impact of mutataion
const obj = { name: "foo" };
const arr = [obj, obj]

console.log(arr);

// Mutating first element
arr[0].name = "bar";

console.log("Contents after mutation", arr);

As you can see, we ended up updating both objects even though we update the one at index 0.
Now I'll spread and mutate:

const obj = { name: "foo" };
const arr = [{...obj}, {...obj}]

console.log(arr);

// Mutating first element
arr[0].name = "bar";

console.log("Contents after mutation", arr);

Only the intended element is mutated now.


There is a lot more to this. In general, Immutability shouldn't be a very big concern if you've started out to learn. But knowing it certainly helps.

For example in React state should not be mutated (reason)

And at last, regarding how to update `aggregatedData'.

const aggregator = () => {
  let aggregateData = [];
  let hasNextPage;
  let page = 1;

  do {
    const { data, nextPage } = pagedData[page - 1];
    aggregateData = [...aggregateData, ...data];
    page = nextPage;
    hasNextPage = nextPage;
  } while (hasNextPage);

  return aggregateData;
}

Since you're prepending data to an array you'll end up mutating it anyway. You can do spread or push or whatever. This all is fine since the array is locally created inside the functions and returned.

Example, where it might be an issue:

const aggregator = (aggregateData) => {
  for (const i = 0; i < 5; i++)
    aggregateData = [...aggregateData, i];

  return aggregateData;
}

const example = () => {
  let arr = [];
  let data = aggregator(arr);
  // if this array is passed to couple other functions too and mutated then it will get hard to track. This is where the issue can occur

}

example();
Sign up to request clarification or add additional context in comments.

3 Comments

Everything you say makes sense and also lead me to further clarify my question. How can I still credit your response even though I would now like additional information?
Ask me what you require. I'd articulate it. We've reached this far...let's take an extra mile.
I'd like to know how I could update the aggregateData array in the above example without mutation? And in general how much concern there might be when mutating a locally defined array (like I did in my example) when trying to respect immutability as much as possible in a codebase? Since the array is defined locally I wonder how mutating the array could really have any negative impact?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.