Everything about the new array methods in JavaScript

javascript4 min

byLucas Santos

This page was machine translated. Read original / Suggest a fix

Once again let’s chat about the main new features in JavaScript! This time we’ll talk about one of the coolest proposals out there right now. Today it’s at stage 3, which means it’ll be live soon!

If you don’t know how JavaScript works, in this video I explain a bit more about the process behind releasing new JavaScript features. If you haven’t watched it yet, I strongly recommend it so you can understand how everything works better!

Play

The problem#

As a lot of people have found out the hard way, arrays and objects in JavaScript are passed by reference because they’re created and stored on the Heap (which I won’t explain here, but this article gives you a good idea). Because of that, they’re created only once and passed to functions as a pointer to the original object.

So when we perform some operation on them, for example reversing an array with reverse(), we always change the original array:

const arr = [1,2,3]
arr.reverse()
console.log(arr) // [3,2,1]

And that’s the cause of tons and tons of problems in most systems. Over time, we learned to use object cloning to create a copy of that array and make the change instead, for example:

const arr = [1,2,3]
const reversed = [...arr].reverse()
console.log(arr) // [1,2,3]
console.log(reversed) // [3,2,1]

When we use the spread operator [... what we’re doing is cloning the array element by element and applying the reverse method to this new array we get back.

And that’s true for several other methods like splice and sort. Why don’t we just change that?

The proposal#

The idea behind this proposal is to add 4 new methods to arrays:

  • Array.prototype.toReversed() -> Array
  • Array.prototype.toSorted(compareFn) -> Array
  • Array.prototype.toSpliced(start, deleteCount, ...items) -> Array
  • Array.prototype.with(index, value) -> Array

These functions don’t need much explaining, but I’ll give you a basic idea of each one so you understand what’s going on. The important part here is that all these functions are non-destructive, meaning they don’t touch the original object: they all return a new array with the changes.

toReversed#

It does the same thing as our second example: it reverses an array and returns the reversed copy of that array, without modifying the original.

let x = [ 1, 2, 3 ];
let y = x.toReversed();
// [ 1, 2, 3 ], [ 3, 2, 1 ]
console.log(x, y);

toSorted#

Just like the previous one and its sort counterpart, this function sorts an array following a sorting function without modifying the original array. By default, the sorting function takes the array and sorts it numerically like this:

let x = [ 5, 3, 4, 2, 1 ];
let y = x.toSorted(); // [ 1, 2, 3, 4, 5 ]

But just like sort, it accepts a sorting function that follows a (a, b) => number signature, where if:

  • The return is >0, a comes after b
  • The return is <0, a comes before b
  • The return is 0, nothing changesYou can find this documentation on MDN.
let x = [
{ value: 0 },
{ value: 4 },
{ value: 2 },
{ value: 3 }
];
// y will be:
// [
// { value: 0 },
// { value: 2 },
// { value: 3 },
// { value: 4 }
// ]
let y = x.toSorted((a, b) => {
return a.value - b.value
});

toSpliced#

The splice method isn’t the same as the slice method. While slice returns a subset of the original array in a new array, splice changes the array’s content in three ways:

  • Adding items anywhere in the array
  • Removing items anywhere in the array
  • Replacing one item with another anywhere in the array

The problem is it also did this to the array it received. This new version returns a fresh copy instead.

The function keeps the same signature, just with a new return type: (start, deleteCount, ...items) => Array, where:

  • start is the position to start counting from, or where the pointer begins
  • deleteCount is the number of items to remove starting from start
  • ...items is an optional parameter that, if passed, sets the new value at position start after removing all the items from deleteCountThis example actually shows very well why these functions are good. If we modified the array in the original array itself, we’d have to recreate x every time.
let x = [ "Cachorro", "Gato", "Zebra", "Morcego", "Tigre", "Leão" ];
// y is [ "Cachorro", "Cobra", "Morcego", "Tigre", "Leão" ]
let y = x.toSpliced(1, 2, "Cobra");
// z is [ "Cachorro, "Tigre", "Leão" ]
let z = x.toSpliced(1, 3);

This example actually shows very well why these functions are good. If we modified the array in the original array itself, we’d have to recreate x every time

with#

This is a new function that simplifies using splice a bit when we only need to modify a single element of the array. Originally, if we wanted to modify this array:

let x = [ "Cachorro", "Gato", "Zebra", "Morcego", "Tigre", "Leão" ];

To show “Cobra” instead of “Gato”, we’d have to do this with splice:

let y = x.toSpliced(1, 1, "Cobra");

But with with we can do this:

// [ 'Cachorro', 'Cobra', 'Zebra', 'Morcego', 'Tigre', 'Leão' ]
x.with(1, "Cobra")

Essentially what we’re saying is: “Take array x, at position 1, and show it with this other value.”

Support#

Support isn’t implemented in every browser yet, but you can use the polyfills available on TC39 to implement this feature. If you’re using Node, you can use core-js to test it out. Your code would look something like this:

require('core-js/proposals/change-array-by-copy')
const sequencia = [1, 2, 3]
console.log(sequencia.toReversed()) // => [3, 2, 1]
console.log(sequencia) // => [1, 2, 3]
const desordenado = new Uint8Array([3, 1, 2])
console.log(desordenado.toSorted()) // => Uint8Array [1, 2, 3]
console.log(desordenado) // => Uint8Array [3, 1, 2]
const precisaDeCorrecao = [1, 1, 3]
console.log(precisaDeCorrecao.with(1, 2)) // => [1, 2, 3]
console.log(precisaDeCorrecao) // => [1, 1, 3]
const spliced = [1, 2, 3]
console.log(spliced.toSpliced(1, 1)) // => [1, 3]
console.log(spliced) // => [1, 2, 3]
let x = [ "Cachorro", "Gato", "Zebra", "Morcego", "Tigre", "Leão" ];
console.log(x.toSpliced(1,1,"Cobra"))
console.log(x.with(1, "Cobra"))

This feature is expected to ship in the next ECMAScript version, along with a bunch of super cool features I’ve already talked about here.