.with()

Creates a new array by modifying one element of the original.

Time to read: 6 min

Briefly

The with() method changes the value of one of the elements in an array and returns a new array, without modifying the original array.

Example

Let's change the element 'white' to 'blue':

        
          
          const colors = ['red', 'green', 'white']const newColors = colors.with(2, 'blue')console.log(newColors)// ['red', 'green', 'blue']// The original array remains unchangedconsole.log(colors)// ['red', 'green', 'white']
          const colors = ['red', 'green', 'white']
const newColors = colors.with(2, 'blue')
console.log(newColors)
// ['red', 'green', 'blue']

// The original array remains unchanged
console.log(colors)
// ['red', 'green', 'white']

        
        
          
        
      

Let's change the element 'white' to 'blue', using a negative index:

        
          
          const colors = ['red', 'green', 'white']const newColors = colors.with(-1, 'blue')console.log(newColors)// ['red', 'green', 'blue']// The original array remains unchangedconsole.log(colors)// ['red', 'green', 'white']
          const colors = ['red', 'green', 'white']
const newColors = colors.with(-1, 'blue')
console.log(newColors)
// ['red', 'green', 'blue']

// The original array remains unchanged
console.log(colors)
// ['red', 'green', 'white']

        
        
          
        
      

How it works

Array.with() takes two arguments:

  • the index of the element to be changed;
  • the new value of the element to be changed.

The index of the element can be:

  • positive — for accessing elements from the beginning of the array;
  • negative — for accessing elements from the end of the array. For example, -1 — the index of the last element, -2 — the second to last, and so on.

Array.with() returns an array with the modified element.

Calling with() without arguments will not result in an error. This is equivalent to calling with(0, undefined):

        
          
          const routes = ['/home', '/settings', '/about']const newRoutes = routes.with()console.log(newRoutes)// [undefined, '/settings', '/about']
          const routes = ['/home', '/settings', '/about']
const newRoutes = routes.with()
console.log(newRoutes)
// [undefined, '/settings', '/about']

        
        
          
        
      

Attempting to call with() with an index value outside acceptable values (index >= array.length || index < -array.length) will result in a RangeError.

        
          
          const authors = ['F. Kafka', 'J. Salinger']try {  console.log(authors.with(2, 'K. Vonnegut'))} catch (err) {  console.error('Caught an error! Here it is: ', err.message)}// Caught an error! Here it is: Invalid index : 2
          const authors = ['F. Kafka', 'J. Salinger']

try {
  console.log(authors.with(2, 'K. Vonnegut'))
} catch (err) {
  console.error('Caught an error! Here it is: ', err.message)
}
// Caught an error! Here it is: Invalid index : 2

        
        
          
        
      

How to understand

When working with arrays, sometimes you need to obtain a new array containing a modified copy of the original array. For example, let's write a function to change the value of the first element of an array using the with() method:

        
          
          const updateFirstItem = (array, value) => {  return array.with(0, value)}
          const updateFirstItem = (array, value) => {
  return array.with(0, value)
}

        
        
          
        
      

Let's check how it works and ensure that the original array remains unchanged.

        
          
          const bears = ['grizzly', 'polar', 'brown']const result = updateFirstItem(bears, 'panda')console.log(result)// ['panda', 'polar', 'brown']console.log(bears)// ['grizzly', 'polar', 'brown']
          const bears = ['grizzly', 'polar', 'brown']
const result = updateFirstItem(bears, 'panda')
console.log(result)
// ['panda', 'polar', 'brown']

console.log(bears)
// ['grizzly', 'polar', 'brown']

        
        
          
        
      

Here is a comparison with a function that changes the value of the first element in the original array:

        
          
          const updateFirstItemDanger = (array, value) => {  const result = array  result[0] = value  return result}
          const updateFirstItemDanger = (array, value) => {
  const result = array
  result[0] = value
  return result
}

        
        
          
        
      

Calling this function will return the same result, but it will modify the original array. The updateFirstItemDanger() function cannot be considered a pure function as it leads to changes in data not belonging to it (defined outside its context). In functional programming, such a change is called a side effect. Functions that cause side effects have a number of drawbacks: less predictability, difficulty in testing. In most cases, such code should be avoided.

        
          
          const bears = ['grizzly', 'polar', 'brown']const result = updateFirstItemDanger(bears, 'panda')console.log(result)// ['panda', 'polar', 'brown']console.log(bears)// Oh no, where has the grizzly bear gone!// ['panda', 'polar', 'brown']
          const bears = ['grizzly', 'polar', 'brown']
const result = updateFirstItemDanger(bears, 'panda')
console.log(result)
// ['panda', 'polar', 'brown']

console.log(bears)
// Oh no, where has the grizzly bear gone!
// ['panda', 'polar', 'brown']

        
        
          
        
      

Note: The reason the original array changes when using the updateFirstItemDanger() function is that the function does not copy the original array received as an argument into a new one, but creates yet another reference to the original array. More about this can be read in the section on “Reference and value storage”.

Tips

💡 with() is a convenient way to avoid modifying (mutation) the original array.

💡 with() simplifies changing elements if they need to be counted from the end of the array rather than from the beginning. For example, this is convenient for changing the last element. Usually, to change the last element of an array, you need to determine its index from the beginning of the array. This requires:

  • knowing the length of the array;
  • calculating the last element's index using the formula lastIndex = arrayLength - 1.

Changing the last element using the traditional approach:

        
          
          const words = ['first', 'second', 'third']const lastIndex = words.length - 1// Creating a copy of the arrayconst newWords = [...words]newWords[lastIndex] = 'last'console.log(newWords)// ['first', 'second', 'last']
          const words = ['first', 'second', 'third']
const lastIndex = words.length - 1

// Creating a copy of the array
const newWords = [...words]

newWords[lastIndex] = 'last'

console.log(newWords)
// ['first', 'second', 'last']

        
        
          
        
      

Here’s how to do it using with():

        
          
          const words = ['first', 'second', 'third']console.log(words.with(-1, 'last'))// ['first', 'second', 'last']
          const words = ['first', 'second', 'third']
console.log(words.with(-1, 'last'))
// ['first', 'second', 'last']

        
        
          
        
      

💡 with() can be used when chaining array processing functions. Each method in the chain receives the result of the previous one. For example:

        
          
          const days = ['', 'Mon', 'Tue', 'Wed', 4]console.log(  days    .filter(item => typeof item === 'string')    .with(0, 'Sun')    .map(item => item.toUpperCase()))// [ 'SUN', 'MON', 'TUE', 'WED' ]
          const days = ['', 'Mon', 'Tue', 'Wed', 4]

console.log(
  days
    .filter(item => typeof item === 'string')
    .with(0, 'Sun')
    .map(item => item.toUpperCase())
)
// [ 'SUN', 'MON', 'TUE', 'WED' ]

        
        
          
        
      

💡 When creating a new array, with() will convert all undefined cells to undefined:

        
          
          const numbers = [0, , 11, 20, , 30]console.log(numbers.with(2, 10))// [ 0, undefined, 10, 20, undefined, 30 ]
          const numbers = [0, , 11, 20, , 30]

console.log(numbers.with(2, 10))
// [ 0, undefined, 10, 20, undefined, 30 ]

        
        
          
        
      

💡 Support for the with() method in major browsers and Node.js has appeared relatively recently. For example, attempting to use with() in Node.js v.18.19.0 will result in an error:

        
          
          const array = ['night','street','lantern']try {  console.log(array.with(-1,'January'))} catch (err) {  console.error('Caught an error! Here it is: ', err.message)}// Caught an error!// Here it is: array.with is not a function
          const array = ['night','street','lantern']
try {
  console.log(array.with(-1,'January'))
} catch (err) {
  console.error('Caught an error! Here it is: ', err.message)
}
// Caught an error!
// Here it is: array.with is not a function