-
Notifications
You must be signed in to change notification settings - Fork 655
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Добавляет ответ на вопрос с собеседования про
reduce()
(#4689)
* Немного правит описание вопроса * Создает директорию и файл для ответа * Создает ответ * Чуть-чуть исправляет коллегу согласно требованиям * Немного убирает лишнее * Добавляет двойной пробел * Расставляет ё * Принимаю предложенное исправление Co-authored-by: Polina Gurtovaya <zloymult@gmail.com> * Правит ответ – поднимает правильное решение на первое место и рассказывает про возможные ошибки ниже. * Отбивает пустые строки, успокаивает спеллер * Возвращает потерявшуюся ё --------- Co-authored-by: Tatiana Fokina <fokinatatian@gmail.com> Co-authored-by: Polina Gurtovaya <zloymult@gmail.com>
- Loading branch information
1 parent
b41ef5c
commit f746225
Showing
3 changed files
with
83 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
### Решение | ||
|
||
Эта задача решается буквально в одну строчку. Давайте посмотрим на решение, а затем немного разберём его. | ||
|
||
```javascript | ||
const sum = (...args) => args.reduce((acc, currentValue) => acc + currentValue); | ||
|
||
sum(1, 2, 3); // 6 | ||
sum('1', 2, 3); // '123' | ||
sum(1); // 1 | ||
``` | ||
|
||
По условиям мы не знаем, какое количество аргументов будет передано. Мы используем синтаксис остаточных параметров (_rest_) в сигнатуре функции. Это позволит преобразовать любое количество аргументов функции в массив `args`. | ||
|
||
С массивом гораздо удобнее работать – мы можем использовать метод [`Array.reduce()`](/js/array-reduce/). Его колбэк будет вызываться для каждого элемента массива, и значение каждого аргумента будет прибавляться к значению в аккумуляторе. Когда начальное значение аккумулятора не указано, метод использует первый элемент массива, а выполнение колбэк начнёт со второго элемента. | ||
|
||
### Какую ошибку легко допустить | ||
|
||
Мы обсудили выше, что [`reduce()`](/js/array-reduce/) в своём колбэке использует аккумулятор – это переменная, которая накапливает в себе результаты прошлых итераций. Часто, используя [`reduce()`](/js/array-reduce/) мы передаём начальное значение аккумулятора. | ||
|
||
```javascript | ||
// Если мы хотим получить из массива объект, то стартовым значением аккумулятора будет объект | ||
|
||
const list = [ | ||
{ key: 'name', value: 'John' }, | ||
{ key: 'age', value: 30 }, | ||
{ key: 'city', value: 'New York' } | ||
]; | ||
|
||
const obj = list.reduce((accumulator, currentItem) => { | ||
accumulator[currentItem.key] = currentItem.value; | ||
return accumulator; | ||
}, {}); | ||
``` | ||
|
||
При решении задач, в которых необходимо складывать значения, часто хочется указать ноль в качестве стартового значения. Это интуитивное и очень понятное на первый взгляд желание – к нулю удобно прибавлять и отрицательные, и положительные числа. | ||
|
||
Давайте разберём такой вариант этой функции, в которой мы укажем ноль как стартовое значение: | ||
|
||
```javascript | ||
const sum = (...args) => args.reduce((acc, currentValue) => acc + currentValue, 0); | ||
|
||
sum(1, 2, 3); // 6 | ||
sum('1', 2, 3); // '0123' | ||
``` | ||
|
||
Пока мы имеем дело с числами – результат ожидаемый. Но почему результат выполнения во втором примере с нулём? | ||
|
||
#### Неявное преобразование типов | ||
|
||
Да, дело в той особенности языка, которая дарит нам столько весёлых шуток про JavaScript. | ||
|
||
Оператор сложения приводит оба операнда к строковому формату в случае, если хотя бы один из них – строка. Таким образом мы и получаем `0125` в примере выше – на первой же итерации строка `'1'` складывается с нулём, заданным как первоначальное значение для [`reduce()`](/js/array-reduce/). | ||
|
||
Давайте вернёмся к первому решению задачи и посмотрим детальнее, как там решается эта проблема. | ||
|
||
```javascript | ||
const sum = (...args) => args.reduce((acc, currentValue) => acc + currentValue); | ||
|
||
sum('1', 2, 3); // '123' | ||
``` | ||
|
||
На первой итерации аккумулятор будет равен значению первого элемента в массиве, а мы получим на первой итерации вот такую операцию: `'1' + 2`. Как я писал выше, бинарный оператор `+` приведёт оба операнда к строковому формату в случае, если хотя бы один из них – строка. | ||
|
||
Пока в массиве встречаются числа – они будут арифметически складываться. Как только в ряду аргументов наш колбэк встретит строку, он начнёт приводить все аргументы к строке и конкатенировать их. | ||
|
||
#### Граничный случай | ||
|
||
Мы успешно справились с главным условием! Но теперь давайте подумаем, как быть, когда в функцию `sum()` не передали вообще никаких аргументов? Просто проверим, что длина массива ненулевая. _Rest_-синтаксис создаст пустой массив, если не будет передано никаких аргументов: | ||
|
||
```javascript | ||
const sum = (...args) => args.length ? args.reduce((acc, currentValue) => acc + currentValue) : 0; | ||
|
||
sum('1', 2, 3); // '123' | ||
sum(1, 2, 3); // 6 | ||
sum(); // 0 | ||
``` | ||
|
||
Мы используем [тернарный оператор](/js/ternary-operator/) для проверки длины массива, а наша функция по-прежнему умещается лишь в одну строку! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters