Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Добавляет доку для метода массива with() #5013

Merged
merged 22 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6e9d117
Добавляет draft доки про метод Array.with()
vitya-ne Dec 5, 2023
63c0ead
Корректировка 1
vitya-ne Dec 5, 2023
e1cd791
Добавляет примеры и пояснения
vitya-ne Dec 5, 2023
8dc893d
Корректирует формулировки и примеры
vitya-ne Dec 6, 2023
3ce0e25
Добавляет подсказку о поддержке метода, bсправляет неточности
vitya-ne Dec 6, 2023
fe2be54
Исправляет ссылку
vitya-ne Dec 6, 2023
42d11a7
Исправлет орфографию: 'ё' -> 'e'
vitya-ne Dec 6, 2023
09c7f45
Немного редачит
TatianaFokina Dec 6, 2023
0c9ddc9
Уважает ё
TatianaFokina Dec 6, 2023
2be813b
Добавляет информацию в раздел people
vitya-ne Dec 6, 2023
b46e43a
Merge remote-tracking branch 'origin/doka/array-with' into doka/array…
vitya-ne Dec 6, 2023
861d100
Упрощает формулировку и добавляет пример
vitya-ne Dec 6, 2023
bc9e592
Корректирует формулировки и примеры
vitya-ne Dec 8, 2023
40b9eae
Update js/array-with/index.md
vitya-ne Dec 29, 2023
a8461ce
Update js/array-with/index.md
vitya-ne Dec 29, 2023
b2bf601
Update js/array-with/index.md
vitya-ne Dec 30, 2023
8012e92
Корректирует после ревью Полины
vitya-ne Dec 30, 2023
708a001
Дополняет примером вызова без аргументов
vitya-ne Dec 30, 2023
043caaa
Дополняет пояснение проблем использования грязной функции
vitya-ne Dec 31, 2023
3080399
Исправляет ошибки
vitya-ne Dec 31, 2023
d3b8046
Поправляет метод консоли для ошибки
vitya-ne Dec 31, 2023
4156f24
Добавляет ачивку
TatianaFokina Jan 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions js/array-with/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
---
title: "`.with()`"
description: "Создаёт новый массив, изменяя один элемент исходного."
authors:
- vitya-ne
related:
- js/arrays
- js/ref-type-vs-value-type
- js/array-find
tags:
- doka
---

## Кратко

Метод `with()` изменяет значение одного из элементов массива и возвращает новый массив, без изменения исходного массива.

## Пример

Изменим элемент 'white' на 'blue':

```js
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', используя отрицательный индекс:

```js
const colors = ['red', 'green', 'white']

const newColors = colors.with(-1, 'blue')

console.log(newColors)
// ['red', 'green', 'blue']

console.log(colors)
// Исходный массив остался прежним
// ['red', 'green', 'white']
```

## Как пишется

`Array.with()` принимает два аргумента:

- индекс элемента, который нужно изменить;
- новое значение изменяемого элемента.

Индекс элемента может быть:

- положительный — для доступа к элементам от начала массива;
- отрицательный — для доступа к элементам с конца массива. Например, `-1` — индекс последнего элемента, `-2` — предпоследнего и т. д.

`Array.with()` возвращает массив с изменённым элементом.

Вызов `with()` без аргументов, не приведёт к ошибке. Это равнозначно вызову `with(0, undefined)`:

```js
const routes = ['/home', '/settings', '/about']
const newRoutes = routes.with()

console.log(newRoutes)
// [undefined, '/settings', '/about']
```

Попытка вызвать `with()` со значением индекса за пределами допустимых значений (`index >= array.length || index < -array.length`) приведёт к возникновению ошибки `RangeError`.

```js
const authors = ['Ф. Кафка', 'Д. Сэлинджер']

try {
console.log(authors.with(2, 'К. Воннегут'))
} catch (err) {
console.error('Поймали ошибку! Вот она: ', err.message)
}
// Поймали ошибку! Вот она: Invalid index : 2
```

## Как понять

При работе с массивами иногда требуется получить новый массив, содержащий изменённую копию исходного массива. Например, напишем функцию для изменения значения первого элемента массива, используя метод `with()`:

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

Проверим, как она работает, и убедимся, что исходный массив остался прежним.

```js
const bears = ['гризли', 'полярный', 'бурый']
const result = updateFirstItem(bears, 'панда')

console.log(result)
// ['панда', 'полярный', 'бурый']

console.log(bears)
// ['гризли', 'полярный', 'бурый']
```

А вот для сравнения функция, меняющая значение первого элемента в исходном массиве:

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

Вызов этой функции вернёт тот же результат, но приведёт к изменению исходного массива. Функция `updateFirstItemDanger()`, не может считаться [чистой](/tools/fp/#chistye-funkcii-i-pobochnye-effekty) (pure), так как приводит к изменению данных, не принадлежащих ей (определённых вне её контекста). В [функциональном программировании](/tools/fp/) такое изменение называется побочный эффект. Функции, вызывающие побочные эффекты, имеют ряд недостатков: меньшая предсказуемость, трудность при тестировании. В большинстве случаев такого кода следует избегать.

```js
const bears = ['гризли', 'полярный', 'бурый']
const result = updateFirstItemDanger(bears, 'панда')

console.log(result)
// ['панда', 'полярный', 'бурый']

console.log(bears)
// Ой, куда пропал мишка гризли!
// ['панда', 'полярный', 'бурый']
```

Обратите внимание: причина изменения исходного массива при использовании функции `updateFirstItemDanger()` в том, что функция не копирует полученный в качестве аргумента исходный массив в новый, а создаёт ещё одну ссылку на исходный массив. Подробнее об этом можно почитать в разделе [Хранение по ссылке и по значению](/js/ref-type-vs-value-type/#mutacii-i-neizmenyaemost).

## Подсказки

💡 `with()` — это удобный способ избежать изменения (мутации) исходного массива.

💡 `with()` - упрощает изменение элемента, если элементы нужно отсчитывать от конца массива, а не от его начала. Например, это удобно для изменения последнего элемента. Обычно для изменения последнего элемента массива нужно определить его индекс от начала массива. Для это потребуется:

- узнать длину массива;
- вычислить индекс последнего элемента, используя формулу `lastIndex = arrayLength - 1`.

Меняем последний элемент используя традиционный подход:

```js
const words = ['первый', 'второй', 'третий']

const lastIndex = words.length - 1
const newWords = [...words] // создаем копию массива

newWords[lastIndex] = 'последний'

console.log(newWords);
// ['первый', 'второй', 'последний']
```

А вот как это можно сделать с использованием `with()`:

```js
const words = ['первый', 'второй', 'третий']

console.log(words.with(-1, 'последний'))
// ['первый', 'второй', 'последний']
```

💡 `with()` может быть использован при объединении функций обработки массива в цепочку вызовов. Каждый метод в цепочке получает результат работы предыдущего. Например:

```js
const days = ['', 'пн', 'вт', 'ср', 4]

console.log(
days
.filter(item => typeof item === 'string')
.with(0, 'вс')
.map(item => item.toUpperCase())
)
// [ 'ВС', 'ПН', 'ВТ', 'СР' ]
```

💡 При создании нового массива `with()` выполнит преобразование всех незаполненных ячеек к `undefined`:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кажется в примере ниже не создается новый массив, а расширяется копия исходного

Suggested change
💡 При создании нового массива `with()` выполнит преобразование всех незаполненных ячеек к `undefined`:
💡 При создании нового массива `with()` выполнит преобразование всех незаполненных ячеек к `undefined`:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я не очень понял твой комент.
with() создаёт новый массив.
Ты имела ввиду, что в примере нужно добавить строку с присвоением ?
вот так:

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

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В твоем примере все хорошо, это я просто не туда посмотрела. Извини пжлст :)


```js
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 приведёт к ошибке:

```js
const array = ['ночь','улица','фонарь']
try {
console.log(array.with(-1,'январь'))
} catch (err) {
console.error('Поймали ошибку! Вот она: ', err.message)
}
// Поймали ошибку! Вот она: array.with is not a function
```
7 changes: 7 additions & 0 deletions people/vitya-ne/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: 'Viktar Nezhbart'
url: https://github.com/vitya-ne
badges:
- first-contribution-small
- workafrolic
---
Loading