Кратко
СкопированоМетод with
изменяет значение одного из элементов массива и возвращает новый массив, без изменения исходного массива.
Пример
СкопированоИзменим элемент 'white' на 'blue':
const colors = ['red', 'green', 'white']const newColors = colors.with(2, 'blue')console.log(newColors)// ['red', 'green', 'blue']// Исходный массив остался прежнимconsole.log(colors)// ['red', 'green', 'white']
const colors = ['red', 'green', 'white'] const newColors = colors.with(2, 'blue') console.log(newColors) // ['red', 'green', 'blue'] // Исходный массив остался прежним console.log(colors) // ['red', 'green', 'white']
Изменим элемент 'white' на 'blue', используя отрицательный индекс:
const colors = ['red', 'green', 'white']const newColors = colors.with(-1, 'blue')console.log(newColors)// ['red', 'green', 'blue']// Исходный массив остался прежнимconsole.log(colors)// ['red', 'green', 'white']
const colors = ['red', 'green', 'white'] const newColors = colors.with(-1, 'blue') console.log(newColors) // ['red', 'green', 'blue'] // Исходный массив остался прежним console.log(colors) // ['red', 'green', 'white']
Как пишется
СкопированоArray
принимает два аргумента:
- индекс элемента, который нужно изменить;
- новое значение изменяемого элемента.
Индекс элемента может быть:
- положительный — для доступа к элементам от начала массива;
- отрицательный — для доступа к элементам с конца массива. Например,
-1
— индекс последнего элемента,-2
— предпоследнего и т. д.
Array
возвращает массив с изменённым элементом.
Вызов with
без аргументов, не приведёт к ошибке. Это равнозначно вызову with
:
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']
Попытка вызвать with
со значением индекса за пределами допустимых значений (index >
) приведёт к возникновению ошибки Range
.
const authors = ['Ф. Кафка', 'Д. Сэлинджер']try { console.log(authors.with(2, 'К. Воннегут'))} catch (err) { console.error('Поймали ошибку! Вот она: ', err.message)}// Поймали ошибку! Вот она: Invalid index : 2
const authors = ['Ф. Кафка', 'Д. Сэлинджер'] try { console.log(authors.with(2, 'К. Воннегут')) } catch (err) { console.error('Поймали ошибку! Вот она: ', err.message) } // Поймали ошибку! Вот она: Invalid index : 2
Как понять
СкопированоПри работе с массивами иногда требуется получить новый массив, содержащий изменённую копию исходного массива. Например, напишем функцию для изменения значения первого элемента массива, используя метод with
:
const updateFirstItem = (array, value) => { return array.with(0, value)}
const updateFirstItem = (array, value) => { return array.with(0, value) }
Проверим, как она работает, и убедимся, что исходный массив остался прежним.
const bears = ['гризли', 'полярный', 'бурый']const result = updateFirstItem(bears, 'панда')console.log(result)// ['панда', 'полярный', 'бурый']console.log(bears)// ['гризли', 'полярный', 'бурый']
const bears = ['гризли', 'полярный', 'бурый'] const result = updateFirstItem(bears, 'панда') console.log(result) // ['панда', 'полярный', 'бурый'] console.log(bears) // ['гризли', 'полярный', 'бурый']
А вот для сравнения функция, меняющая значение первого элемента в исходном массиве:
const updateFirstItemDanger = (array, value) => { const result = array result[0] = value return result}
const updateFirstItemDanger = (array, value) => { const result = array result[0] = value return result }
Вызов этой функции вернёт тот же результат, но приведёт к изменению исходного массива. Функция update
, не может считаться чистой (pure) функцией, так как приводит к изменению данных, не принадлежащих ей (определённых вне её контекста). В функциональном программировании такое изменение называется побочный эффект. Функции, вызывающие побочные эффекты, имеют ряд недостатков: меньшая предсказуемость, трудность при тестировании. В большинстве случаев такого кода следует избегать.
const bears = ['гризли', 'полярный', 'бурый']const result = updateFirstItemDanger(bears, 'панда')console.log(result)// ['панда', 'полярный', 'бурый']console.log(bears)// Ой, куда пропал мишка гризли!// ['панда', 'полярный', 'бурый']
const bears = ['гризли', 'полярный', 'бурый'] const result = updateFirstItemDanger(bears, 'панда') console.log(result) // ['панда', 'полярный', 'бурый'] console.log(bears) // Ой, куда пропал мишка гризли! // ['панда', 'полярный', 'бурый']
Обратите внимание: причина изменения исходного массива при использовании функции update
в том, что функция не копирует полученный в качестве аргумента исходный массив в новый, а создаёт ещё одну ссылку на исходный массив. Подробнее об этом можно почитать в разделе «Хранение по ссылке и по значению».
Подсказки
Скопировано💡 with
— это удобный способ избежать изменения (мутации) исходного массива.
💡 with
упрощает изменение элемента, если элементы нужно отсчитывать от конца массива, а не от его начала. Например, это удобно для изменения последнего элемента. Обычно для изменения последнего элемента массива нужно определить его индекс от начала массива. Для это потребуется:
- узнать длину массива;
- вычислить индекс последнего элемента, используя формулу
last
.Index = array Length - 1
Меняем последний элемент, используя традиционный подход:
const words = ['первый', 'второй', 'третий']const lastIndex = words.length - 1// Создаём копию массиваconst newWords = [...words]newWords[lastIndex] = 'последний'console.log(newWords)// ['первый', 'второй', 'последний']
const words = ['первый', 'второй', 'третий'] const lastIndex = words.length - 1 // Создаём копию массива const newWords = [...words] newWords[lastIndex] = 'последний' console.log(newWords) // ['первый', 'второй', 'последний']
А вот как это можно сделать с использованием with
:
const words = ['первый', 'второй', 'третий']console.log(words.with(-1, 'последний'))// ['первый', 'второй', 'последний']
const words = ['первый', 'второй', 'третий'] console.log(words.with(-1, 'последний')) // ['первый', 'второй', 'последний']
💡 with
может быть использован при объединении функций обработки массива в цепочку вызовов. Каждый метод в цепочке получает результат работы предыдущего. Например:
const days = ['', 'пн', 'вт', 'ср', 4]console.log( days .filter(item => typeof item === 'string') .with(0, 'вс') .map(item => item.toUpperCase()))// [ 'ВС', 'ПН', 'ВТ', 'СР' ]
const days = ['', 'пн', 'вт', 'ср', 4] console.log( days .filter(item => typeof item === 'string') .with(0, 'вс') .map(item => item.toUpperCase()) ) // [ 'ВС', 'ПН', 'ВТ', 'СР' ]
💡 При создании нового массива with
выполнит преобразование всех незаполненных ячеек к 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 ]
💡 Поддержка метода with
в основных браузерах и в Node.js появилась сравнительно недавно. Например, попытка использовать with
в Node.js v.18.19.0 приведёт к ошибке:
const array = ['ночь','улица','фонарь']try { console.log(array.with(-1,'январь'))} catch (err) { console.error('Поймали ошибку! Вот она: ', err.message)}// Поймали ошибку!// Вот она: array.with is not a function
const array = ['ночь','улица','фонарь'] try { console.log(array.with(-1,'январь')) } catch (err) { console.error('Поймали ошибку! Вот она: ', err.message) } // Поймали ошибку! // Вот она: array.with is not a function