with allow you to perform operations on arrays by without changing the data in place, but by making a copy and changing that copy. Read on to learn the difference and how to start using them in your projects.
Mutation and side effects
The Array object has always had some oddities. Methods like
splice change the array in place. Other methods like
filter create a copy of the array and then operate on the copy. When you perform an operation on an object that mutates it, that is a side effect and can cause unexpected behaviour elsewhere in your system.
As an example, this is what happens when you reverse an array.
As you can see, the original array was reversed and even though we assigned the result of reversing the array to a new variable, both variables simply point to the same array.
Mutating arrays and React
One of the best known issues with array methods that mutate the array is when you use them in a React component. You can't mutate an array and then try to set it as a new state because the array itself is the same object and this won't trigger a new render. Instead you need to copy the array first, then mutate the copy and set that as the new state. The React docs have a whole page explaining how to update arrays in state because of this.
Copy first, then mutate
The way to work around this has been to copy the array first, then mutate it. There are several different ways to make a copy of an array, including:
Array.from, the spread operator, or calling the
slice function with no arguments.
It's great that there is a workaround, but having to remember to perform one of the different copy methods first isn't great.
New methods change by copy
That's where the new methods come in. Each of
with copy the original array for you, change the copy and return it. It will make performing each of these actions easier to write as you only need to remember to call one function and easier to read as you don't need to parse one of four methods of copying an array first. So what do each of the methods do?
toSorted function returns a new, sorted array.
sort function has some unexpected behaviour and aside from copying,
toSorted shares that behaviour. You still need to be careful if you are sorting numbers or strings with accented characters. Make sure you provide a comparator function (like
localeCompare) that will produce the results you are looking for.
toReversed function returns a new array sorted in the reverse order.
Sonar has a rule that covers misleading use of methods like
reverse. Assigning the result of
reverse to a new variable is misleading because the original array was mutated too. Now you can use
toSorted to copy the array and mutate the copy instead..
toSpliced function is a bit different to its original version
splice changes the existing array by deleting and adding elements at the provided index and returns an array containing the deleted elements from the array.
toSpliced returns a new array without the removed elements and including any added elements. Here's how it works:
If you are using
splice for its return value, then
toSpliced will not be a drop in replacement. If you want to know the deleted elements without altering the original array, then you should use the copying method
splice takes different arguments to
splice takes an index and the number of elements after that index to remove and
slice takes two indexes, the start and the end. If you wanted to use
toSpliced in place of
splice but also get the elements that are deleted you could apply
slice to the original array, like this:
with function is the copy equivalent of using square bracket notation to change one element of an array. So, instead of directly changing the array like this:
You can copy the array and make the change
Not just arrays
The regular array object isn't the only one benefitting from these new methods. You can also use
with on any
TypedArray. That is everything from
TypedArrays do not have a
splice method, so they are not getting a matching
I mentioned at the top that methods like
concat already perform copying operations. There is a difference between those methods and the new copying methods though. If you extend the built in
Array object and use
concat on an instance, it will return a new instance of the same type. If you extend an
Array and use
with the result will be a plain
You can turn that back into your custom
Array with the use of
While the ECMAScript 2023 spec is very new, there is already good support for these new array methods. Chrome 110, Safari 16.3, Node.js 20, and Deno 1.31 all support all four methods and there are polyfills and shims available for platforms that don't yet have support.
It's great to see additions like this to the ECMAScript standard that make it easier for us to write predictable code. There are a few other proposals that made it into ES2023 that you should check out if you're interested. Check out the whole TC39 proposals repository if you want to see what else is close to joining the spec.