Как стать автором
Обновить
78.6
Рейтинг
Plarium
Разработчик мобильных и браузерных игр

Функции высшего порядка в JavaScript: что это такое?

Блог компании PlariumJavaScriptHTMLNode.JS
Перевод
Автор оригинала: Sukhjinder Arora
Представляем вам перевод статьи Sukhjinder Arora, опубликованной на ресурсе Bits and Pieces. Узнайте под катом о функциях высшего порядка в JavaScript и о некоторых других функциях, встроенных в этот язык.


Фото NESA by Makers с сайта Unsplash

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

Именно благодаря способности работать с функциями высшего порядка, JavaScript подходит для функционального программирования.

Функции высшего порядка широко распространены в языке JavaScript. Если вы проработали с ним какое-то время, весьма вероятно, что вы использовали такие функции, даже не догадываясь об этом.

Чтобы получить полное представление о функциях высшего порядка, вам прежде всего нужно понять, что такое функциональное программирование и функции первого класса.

Совет: многократное применение функций JavaScript часто ведет к появлению дубликатов. Чтобы избежать этого, воспользуйтесь Bit (GitHub). Вы сможете с легкостью находить новые функции, делиться ими и применять их повторно с минимальными изменениями в управлении. Пробуйте, не стесняйтесь.

Что такое функциональное программирование


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

Функциональное программирование производится на таких языках, как JavaScript, Haskell, Clojure, Scala и Erlang.

Что такое функции первого класса


Обучаясь работе с JavaScript, вы, скорее всего, слышали, что для него функции — это граждане первого класса. Дело в том, что в JavaScript, как и в любом другом языке функционального программирования, функции являются объектами.

Конкретно для JavaScript функции — это объекты особого рода (объекты Function, или функторы). Например:

function greeting() {
  console.log('Hello World');
}
// Invoking the function
greeting();  // prints 'Hello World'

Чтобы показать, что функции в JavaScript являются объектами, мы можем проделать что-то вроде этого:

// We can add properties to functions like we do with objects
greeting.lang = 'English';
// Prints 'English'
console.log(greeting.lang);

Примечание: хотя вышеописанное и прекрасно работает в JavaScript, злоупотреблять подобным не стоит. Нельзя присваивать случайные свойства функторам — лучше используйте обычные объекты.

В JavaScript все, что вы можете проделать с другими сущностями, такими как объект, строка (string) или число, применимо и к функциям. Их можно передавать, в том числе в качестве аргументов другим функциям (тогда они называются callback-функциями или функциями обратного вызова), присваивать их переменным и так далее. Вот почему функции JavaScript называются функциями первого класса.

Присваивание функций переменным


JavaScript позволяет присваивать функции переменным. Например:

const square = function(x) {
  return x * x;
}
// prints 25
square(5);

Также их можно передавать. Например:

const foo = square;
// prints 36
foo(6);

Передача функций в качестве аргументов


Мы можем передавать функции в качестве аргументов другим функциям. Например:

function formalGreeting() {
  console.log("How are you?");
}
function casualGreeting() {
  console.log("What's up?");
}
function greet(type, greetFormal, greetCasual) {
  if(type === 'formal') {
    greetFormal();
  } else if(type === 'casual') {
    greetCasual();
  }
}
// prints 'What's up?'
greet('casual', formalGreeting, casualGreeting);

Итак, теперь, зная, что такое функции первого класса, давайте обратимся к функциям высшего порядка в JavaScript.

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


Функции высшего порядка — это функции, которые работают с другими функциями, принимая функцию как аргумент или возвращая функцию как результат.

Примерами функций высшего порядка, которые уже встроены в язык, являются Array.prototype.map, Array.prototype.filter и Array.prototype.reduce.

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


Давайте рассмотрим несколько примеров встроенных функций высшего порядка и сравним их с решениями, при которых функции высшего порядка не используются.

Array.prototype.map
Метод map() создает новый массив с результатом вызова передаваемой функции для каждого элемента начального массива. Метод map() берет каждое значение callback-функции и создает новый массив, используя эти значения.

Callback-функция, передаваемая методу map(), принимает три аргумента: element, index и array.

Рассмотрим это на нескольких примерах.

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

Без функции высшего порядка:

const arr1 = [1, 2, 3];
const arr2 = [];
for(let i = 0; i < arr1.length; i++) {
  arr2.push(arr1[i] * 2);
}
// prints [ 2, 4, 6 ]
console.log(arr2);

При помощи функции высшего порядка map:

const arr1 = [1, 2, 3];
const arr2 = arr1.map(function(item) {
  return item * 2;
});
console.log(arr2);

Код можно сделать еще короче при помощи стрелочной функции

const arr1 = [1, 2, 3];
const arr2 = arr1.map(item => item * 2);
console.log(arr2);

Пример №2
Скажем, у нас есть массив, содержащий годы рождения нескольких людей, и из него мы хотим создать новый массив, в котором будут их возрасты.

Без функции высшего порядка:

const birthYear = [1975, 1997, 2002, 1995, 1985];
const ages = [];
for(let i = 0; i < birthYear.length; i++) {
  let age = 2018 - birthYear[i];
  ages.push(age);
}
// prints [ 43, 21, 16, 23, 33 ]
console.log(ages);

При помощи функции высшего порядка map:

const birthYear = [1975, 1997, 2002, 1995, 1985];
const ages = birthYear.map(year => 2018 - year);
// prints [ 43, 21, 16, 23, 33 ]
console.log(ages);

Array.prototype.filter
Метод filter() создает новый массив со всеми элементами, прошедшими проверку, задаваемую в передаваемой функции. Callback-функция, передаваемая методу filter(), принимает три аргумента: element, index и array.

Рассмотрим это на нескольких примерах.

Пример №1
Представим, что у нас есть массив, содержащий объекты со свойствами «имя» и «возраст». Из него мы хотим создать новый массив, в котором будут указаны только совершеннолетние (от восемнадцати и старше).

Без функции высшего порядка:

const persons = [
  { name: 'Peter', age: 16 },
  { name: 'Mark', age: 18 },
  { name: 'John', age: 27 },
  { name: 'Jane', age: 14 },
  { name: 'Tony', age: 24},
];
const fullAge = [];
for(let i = 0; i < persons.length; i++) {
  if(persons[i].age >= 18) {
    fullAge.push(persons[i]);
  }
}
console.log(fullAge);

При помощи функции высшего порядка filter:

const persons = [
  { name: 'Peter', age: 16 },
  { name: 'Mark', age: 18 },
  { name: 'John', age: 27 },
  { name: 'Jane', age: 14 },
  { name: 'Tony', age: 24},
];
const fullAge = persons.filter(person => person.age >= 18);
console.log(fullAge);

Array.prototype.reduce
Метод reduce применяет функцию к каждому значению массива, сводя его к одному значению. Метод reduce принимает два аргумента:
  1. callback-функцию, которую требуется обработать;
  2. необязательный параметр initialValue (первый аргумент при первом вызове функции).

Callback-функция принимает четыре аргумента: accumulator, currentValue, currentIndex, sourceArray.

Если параметр initialValue был передан, аргумент accumulator будет равен аргументу initialValue, а аргумент currentValue — первому элементу массива.

Если параметр initialValue передан не был, аргумент accumulator будет равен первому элементу массива, а в качестве аргумента currentValue будет взят второй элемент массива.

Пример №1
Предположим, нам нужно найти сумму чисел массива.

При помощи функции высшего порядка reduce:

const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
});
// prints 25
console.log(sum);

Каждый раз, когда callback-функция применяется к каждому значению из массива, аргумент accumulator сохраняет результат предыдущего действия, возвращенный функцией, а currentValue принимает следующее значение массива. По завершении работы результат сохраняется в переменной sum.

Кроме того, мы можем передать этой функции начальное значение:

const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
}, 10);
// prints 35
console.log(sum);

Без функции высшего порядка:

const arr = [5, 7, 1, 8, 4];
let sum = 0;
for(let i = 0; i < arr.length; i++) {
  sum = sum + arr[i];
}
// prints 25
console.log(sum);

Как видите, при помощи функции высшего порядка код можно сделать аккуратнее, короче и емче.

Создание собственной функции высшего порядка


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

Представим, что в JavaScript не было бы собственного метода map. Мы могли бы построить его самостоятельно, тем самым создав собственную функцию высшего порядка.

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

const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C'];

function mapForEach(arr, fn) {
  const newArray = [];
  for(let i = 0; i < arr.length; i++) {
    newArray.push(
      fn(arr[i])
    );
  }
  return newArray;
}
const lenArray = mapForEach(strArray, function(item) {
  return item.length;
});
// prints [ 10, 6, 3, 4, 1 ]
console.log(lenArray);

В приведенном примере мы создали функцию высшего порядка mapForEach, которая принимает в качестве аргументов массив и callback-функцию fn. Эта функция циклично применяется к каждому элементу массива и вызывает callback-функцию fn в рамках вызова функции newArray.push в каждой итерации.

Callback-функция fn принимает текущий элемент начального массива и возвращает значение длины этого элемента, которое сохраняется внутри нового массива newArray. После завершения итерации массив newArray возвращается в качестве результата и назначается массивом lenArray.

Заключение


Мы узнали, что такое функции высшего порядка, и рассмотрели некоторые встроенные в язык функции. Также мы узнали, как создавать собственные функции высшего порядка.

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

Вот, собственно, и все. Если данная статья показалась вам полезной, вы можете также подписаться на меня на Medium и в Twitter. Не стесняйтесь — комментируйте, если у вас есть вопросы! Я буду рад помочь. :)
Теги:javascriptjavasoftware developmentweb-разработкапрограммированиеnode.jsfunctionобучениеновичок javaновичкамфункции высшего порядка
Хабы: Блог компании Plarium JavaScript HTML Node.JS
Всего голосов 23: ↑19 и ↓4 +15
Просмотры8.7K

Похожие публикации

.Net Software Developer in Big Data
PLARIUMМожно удаленно
Data Scientist
PLARIUMМожно удаленно
Data Engineer
PLARIUMКраснодарМожно удаленно
Lead of Localization Department
PLARIUMКраснодар
UX Designer
PLARIUMКраснодар

Лучшие публикации за сутки

Информация

Дата основания
2009
Местоположение
Израиль
Сайт
company.plarium.com
Численность
1 001–5 000 человек
Дата регистрации

Блог на Хабре