Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Функции высшего порядка

В JavaScript встроен метод sort, который сортирует массив. По умолчанию, этот метод сортирует массив весьма замысловатым способом: приводит каждый элемент массива к строковому типу и сравнивает полученные строки на основе порядка следования кодовых точек Unicode. Подобная сортировка подходит для простых ситуаций, например для числовых значений, но перестает работать в случае более сложного сравнения, например тогда, когда каждый элемент массива объект.

Давайте вообразим ситуацию: на вход в программу приходит список пользователей, который нужно отсортировать по возрасту и вывести на экран.

const users = [
  { name: 'Igor', age: 19 },
  { name: 'Danil', age: 1 },
  { name: 'Vovan', age: 4 },
  { name: 'Matvey', age: 16 },
];

Сортировка по умолчанию не может правильно отсортировать подобный массив. Причем это касается любого вида сортировки, который мог бы нам понадобится. Мы можем захотеть сортировать по любому параметру (или даже по набору параметров) и в любом порядке. Сортировки нужны часто, и многие из них довольно сложны.

В языках где функции не являются данными (объектами первого рода) нам пришлось бы для каждого вида сортировки реализовывать свою собственную функцию sort(). Но в JavaScript есть способ лучше. Посмотрим на определение встроенного метода sort():

arr.sort([compareFunction])

Он принимает необязательный параметр compareFunction(), функцию, которая указывает как сортировать данный массив. Общая идея состоит в том, что нам не нужно реализовывать алгоритм сортировки каждый раз для каждой ситуации, ведь он не меняется. Всё, что меняется — элементы, которые сравниваются между собой в процессе сортировки. И метод sort() делегирует взаимодействие с этими элементами вызываемому коду:

const users = [
  { name: 'Igor', age: 19 },
  { name: 'Danil', age: 1 },
  { name: 'Vovan', age: 4 },
  { name: 'Matvey', age: 16 },
];

// Функция принимает на вход сравниваемые элементы массива
const compare = (a, b) => {
  if (a.age === b.age) {
    return 0;
  }

  return a.age > b.age ? 1 : -1;
};

users.sort(compare);

console.log(users);
// => [ { name: 'Danil', age: 1 },
//      { name: 'Vovan', age: 4 },
//      { name: 'Matvey', age: 16 },
//      { name: 'Igor', age: 19 } ]

https://repl.it/@hexlet/js-functions-high-order-functions-sort

Метод sort() выполняет всю работу по непосредственному перемещению элементов в массиве. Но то, какой элемент больше или меньше, — зависит от программиста. Достигается подобная схема за счёт той самой пользовательской функции, которая передаётся при вызове sort(). Эта функция принимает на вход два параметра — sort() отдаёт в неё два элемента, которые она сравнивает в данный момент. В нашем случае элементы — пользователи. Ваша задача — внутри этой функции посчитать, что больше или меньше, и сделать следующее: Если элементы равны, то нужно вернуть вернуть 0, если первый элемент больше второго, то считается, что они отсортированы неправильно, и возвращается 1, иначе возвращается -1, а sort() производит их сортировку.

Из кода видно, что внутри функции сравнение идёт по свойству age переданных пользователей. Нетрудно догадаться, что эта функция вызывается внутри sort() множество раз (а именно на каждое сравнение). Как только она начнёт возвращать -1 для каждой пары элементов — сортировка завершена.

Метод sort() относится к так называемым функциям высшего порядка (higher order functions). Функции высшего порядка — это функции, которые либо принимают, либо возвращают другие функции, либо делают всё сразу. Такие функции, как правило, реализуют некий обобщённый алгоритм (например, сортировку), а ключевую часть логики делегируют программисту через функцию. Главный плюс от применения таких функций — серьёзное повышение коэффициента повторного использования кода.

В примере выше необязательно создавать константу для функции. Говоря откровенно, их вообще редко записывают в константы. Типичное использование выглядит как прямая передача функции в функцию:

users.sort((a, b) => {
  if (a.age === b.age) {
    return 0;
  }
  return a.age > b.age ? 1 : -1;
});

// То же самое но используя функцию Math.sign
users.sort((a, b) => Math.sign(a.age - b.age));

Потратьте немного времени, чтобы понять, где заканчивается одна функция и начинается другая. Подобный код мы начнём использовать уже со следующего урока.

Осталось рассмотреть то, как происходит вызов внутри. С точки зрения синтаксиса ничего нового не будет.

const say = (fn) => {
  const message = fn();
  console.log(message);
};
// или так:
// const say = (fn) => console.log(fn());

const myCallbackFn = () => 'hi!';
say(myCallbackFn); // => hi!
// или так:
// say(() => 'hi!');

Функция say() делает вызов функции, находящейся внутри параметра fn(). В нашем примере функция возвращает строку, которая тут же выводится на экран.

Функции высшего порядка настолько удобны в большинстве языков, что практически целиком могут заменить использование тех же циклов. Например, канонический код на JS выглядит так:

users
  .filter((user) => user.age >= 16)
  .map((user) => `${user.name} is ${user.age} years old`)
  .join('\n');
// => Igor is 19 years old
//    Matvey is 16 years old

В этом коде присутствует 2 функции высшего порядка (filter() и map()), 2 функции-аргументы и два прохода (это делают функции высшего порядка) по списку пользователей. Код весьма выразителен и лаконичен. Скоро вы научитесь писать код также.

В следующих уроках мы рассмотрим три самые главные функции высшего порядка, которыми можно решать практически любые задачи. Две из них используются в примере выше, это map() и filter(), а третья — reduce(). Они все доступны в стандартной библиотеке JavaScript.

Постепенно, используя эти функции, мы полностью уйдем от использование циклов. JavaScript язык в котором логика работы строится на функциях высшего порядка. К ним нужно привыкать и постепенно внедрять в свой арсенал разработчика. Начиная со следующего урока в курсах JavaScript циклы больше не используются. Посмотрите на пример реального кода и обратите внимание на отсутствие циклов. Скоро вы научитесь писать его также.


Дополнительные материалы

  1. Функция высшего порядка

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу нужна профессиональная подписка

Профессиональная подписка откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, даст возможность обращаться за помощью к менторам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».