
Как веб-разработчик, вы всегда должны стремиться изучать новые методы и открывать способы более эффективной работы с JavaScript.
Одним из таких приемов есть использование функций высшего порядка. Функции высшего порядка – это функции, которые принимают одну или несколько функций в качестве аргументов или возвращают функцию как результат.
В этой статье мы рассмотрим, что такое функция высшего порядка, преимущества их использования и как использовать их в практических программах.
Что такое функция высшего порядка?
Функция высшего порядка – это функция, которая принимает одну или несколько функций в качестве аргументов или возвращает функцию как результат.
Существует несколько типов функций высшего порядка, таких как отображение и уменьшение. Мы обсудим это позже в настоящем руководстве. Но перед этим давайте поначалу глубже погрузимся в то, что такое функции высшего порядка.
// Callback function, passed as a parameter in the higher order function
function callbackFunction(){
console.log('I am a callback function');
}
// higher order function
function higherOrderFunction(func){
console.log('I am higher order function')
func()
}
higherOrderFunction(callbackFunction);
В приведенном выше коде higherOrderFunction()
это HOF, поскольку мы передаем ему функцию обратного вызова как параметр.
Приведенный выше пример достаточно прост, не правда ли? Итак, давайте расширим его дальше и посмотрим, как вы можете использовать HOF для написания более лаконичного и модульного кода.
Как работают функции высшего порядка
Итак, допустим, я хочу, чтобы вы написали функцию, которая вычисляет площадь и диаметр круга. Как начинающий, первое решение, которое приходит нам в голову, это написать каждую отдельную функцию для вычисления площади или диаметра.
const radius = [1, 2, 3];
// function to calculate area of the circle
const calculateArea = function (radius) {
const output = [];
for(let i = 0; i< radius.length; i++){
output.push(Math.PI * radius[i] * radius[i]);
}
return output;
}
// function to calculate diameter of the circle
const calculateDiameter = function (radius) {
const output = [];
for(let i = 0; i< radius.length; i++){
output.push(2 * radius[i]);
}
return output;
}
console.log(calculateArea(radius));
console.log(calculateDiameter(radius))
Но заметили ли вы проблему с приведенным выше кодом? Не пишем ли мы почти ту же функцию снова и снова с несколько иной логикой? Кроме того, функции, которые мы написали, нельзя использовать повторно, не правда ли?
Итак, давайте посмотрим, как мы можем написать тот же код с помощью HOF:
const radius = [1, 2, 3];
// logic to clculate area
const area = function(radius){
return Math.PI * radius * radius;
}
// logic to calculate diameter
const diameter = function(radius){
return 2 * radius;
}
// a reusable function to calculate area, diameter, etc
const calculate = function(radius, logic){
const output = [];
for(let i = 0; i < radius.length; i++){
output.push(logic(radius[i]))
}
return output;
}
console.log(calculate(radius, area));
console.log(calculate(radius, diameter));
Теперь, как вы видите в коде выше, мы написали только одну функцию calculate()
вычислить площадь и диаметр круга. Нам нужно только написать логику и передать ее calculate()
и функция выполнит свою работу.
Код, который мы написали с помощью HOF, является лаконичным и модульным. Каждая функция выполняет свою работу, и мы здесь ничего не повторяем.
Предположим, что в будущем мы захотим написать программу для вычисления окружности круга. Мы можем просто написать логику вычисления окружности и передать ее в calculate()
функция.
const circumeference = function(radius){
return 2 * Math.PI * radius;
}
console.log(calculate(radius, circumeference));
Как использовать функции высшего порядка
Вы можете использовать функции высшего порядка разными способами.
При работе с массивами можно использовать map()
, reduce()
, filter()
и sort()
функции обработки и преобразования данных в массиве.
При работе с объектами можно использовать Object.entries()
функция создания нового массива из объекта.
При работе с функциями можно использовать compose()
функция для создания сложных функций из более простых.
Как использовать некоторые важные функции высшего порядка
Есть разные встроенные HOF, и некие из самых распространенных это map(), filter() и reduce(). Итак, давайте разберемся в каждом из них поподробнее.
Как использовать map()
в JavaScript
The map()
функция принимает массив значений и применяет преобразование к каждому значению в массиве. Это не изменяет оригинальный массив. Его часто используют для преобразования массива данных в новый массив с другой структурой.
Разберемся на примерах.
Пример 1: Предположим, мы хотим добавить 10 к каждому элементу в массиве. Мы можем использовать map()
метод отображения каждого элемента в массиве, чтобы добавить к нему 10.
const arr = [1, 2, 3, 4, 5];
const output = arr.map((num) => num += 10)
console.log(arr); // [1, 2, 3, 4, 5]
console.log(output); // [11, 12, 13, 14, 15]
В приведенном выше примере arr
это массив из пяти элементов: 1, 2, 3, 4 и 5. map
это метод, который мы используем для применения функции к каждому элементу в массиве, и возвращает новый массив с измененными элементами.
Передаваемая функция обратного вызова map
использует синтаксис функции стрелки и принимает один аргумент num
. Эта функция добавляет 10 к num
(каждый элемент в массиве) и возвращает результат.
Пример 2: Здесь у нас есть ряд пользователей. Предположим, что нам нужны только имя и фамилия. Мы можем просто использовать map()
метод извлечения его из users
массив.
const users = [
{firstName: 'John', lastName: 'Doe', age: 25},
{firstName: 'Jane', lastName: 'Doe', age: 30},
{firstName: 'Jack', lastName: 'Doe', age: 35},
{firstName: 'Jill', lastName: 'Doe', age: 40},
{firstName: 'Joe', lastName: 'Doe', age: 45},
]
const result = users.map((user) => user.firstName + ' ' + user.lastName)
console.log(result); // ['John Doe', 'Jane Doe', 'Jack Doe', 'Jill Doe', 'Joe Doe']
В приведенном выше коде users
это массив объектов, представляющих юзеров. Каждый объект имеет три свойства: firstName
, lastName
и age
.
Мы отображаем каждого пользователя с помощью map()
метод извлечения свойств firstName
и lastName
.
Функция обратного вызова принимает один аргумент user
который представляет элемент в users
массив(объект).
Функция объединяет firstName
и lastName
свойства user
и возвращает результат.
Как использовать filter()
в JavaScript
The filter()
функция принимает массив и возвращает новый массив только со значениями, отвечающими определенным критериям. Он также не изменяет исходный массив. Его часто используют для выбора подмножества данных из массива на основе определенных критериев.
Пример 1: Вы можете использовать filter()
чтобы вернуть только нечетные числа из массива чисел.
const arr = [1, 2, 3, 4, 5];
const output = arr.filter((num) => num % 2) // filter out odd numbers
console.log(arr); // [1, 2, 3, 4, 5]
console.log(output); // [1, 3, 5]
В приведенном выше коде arr
это массив из пяти элементов: 1, 2, 3, 4 и 5. filter
это метод, используемый для создания нового массива с элементами, проходящими тест, указанный в предоставленной функции обратного вызова.
Эта функция обратного вызова проверяет, num
является нечетным путем проверки, не делится ли оно на 2 (num % 2
). Если num
не делится на 2, функция возвращает true
иначе возвращается false
.
Когда filter
вызывается arr
он применяет эту функцию к каждому элементу в массиве, создавая новый массив только с вернувшимися элементами. true
или передал указанное условие при передаче в функцию. Оригинальный arr
остается неизменным и возвращает результат.
Пример 2: Вы можете использовать filter()
чтобы вернуть в массиве только пользователей старше 30 лет.
const users = [
{firstName: 'John', lastName: 'Doe', age: 25},
{firstName: 'Jane', lastName: 'Doe', age: 30},
{firstName: 'Jack', lastName: 'Doe', age: 35},
{firstName: 'Jill', lastName: 'Doe', age: 40},
{firstName: 'Joe', lastName: 'Doe', age: 45},
]
// Find the users with age greater than 30
const output = users.filter(({age}) => age > 30)
console.log(output); // [{firstName: 'Jack', lastName: 'Doe', age: 35}, {firstName: 'Jill', lastName: 'Doe', age: 40}, {firstName: 'Joe', lastName: 'Doe', age: 45}]
В приведенном выше коде users
это массив объектов, представляющих юзеров. Каждый объект имеет три свойства: firstName
, lastName
и age
.
filter
называется на users
массив и применяет функцию обратного вызова к каждому элементу в массиве.
Функция принимает один аргумент, деструктурированный объект к одному свойству age
. Эта функция проверяет, age
больше 30. Если это так, функция возвращает true
иначе возвращается false
.
Когда filter
вызывается users
он применяет эту функцию к каждому элементу в массиве, создавая новый массив только с вернувшимися элементами. true
при передаче функции и возвращает результат. Оригинальный users
массив остается неизменным.
Как использовать reduce()
в JavaScript
The reduce()
метод вроде бы потрясающий. Если вы наткнулись reduce()
метод раньше и поначалу не понял, это вполне нормально.
Но не волнуйтесь – здесь мы научимся этому на нескольких примерах, и я приложу все усилия, чтобы вы поняли этот метод.
У вас может возникнуть сомнение, почему мы используем reduce()
метод. Поскольку существует много методов, как мы можем решить, какой из них использовать и когда?
В случае с reduce()
Вы должны его использовать, если вы хотите выполнить определенную операцию над элементами массива и вернуть единое значение как результат. Единое значение относится к накопленному результату многократного применения функции к элементам последовательности.
Например, вы можете использовать reduce()
чтобы подытожить все элементы в массиве, найти максимальное или минимальное значение, объединить несколько объектов в один объект или сгруппировать разные элементы в массиве.
Теперь разберемся во всем этом на примерах.
Пример 1: Использование reduce()
чтобы подытожить все элементы в массиве:
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((total, currentValue) => {
return total + currentValue;
}, 0)
console.log(sum); // 15
В этом примере reduce()
метод называется на numbers
массив и передается функция обратного вызова, принимающая два аргумента: total
и currentValue
.
The total
аргумент – это накопление значений, которые были возвращены функцией на данный момент, и currentValue
текущий обрабатываемый элемент массива.
The reduce()
В этом случае метод также принимает исходное значение как второй аргумент 0
которое используется как первоначальное значение total
для первой итерации
В каждой итерации функция добавляет текущее значение в итог и возвращает новое значение итога.
The reduce()
метод затем использует возвращенное значение как total
для последующей итерации пока он не обработает все элементы в массиве.
Наконец он возвращает окончательное значение total, которое является суммой всех элементов в массиве.
Пример 2: Использование reduce()
чтобы найти максимальное значение в массиве:
let numbers = [5, 20, 100, 60, 1];
const maxValue = numbers.reduce((max, curr) => {
if(curr > max) max = curr;
return max;
});
console.log(maxValue); // 100
В этом примере мы снова имеем два аргумента max
и curr
в функции обратного вызова Обратите внимание, что мы не передали второй параметр в reduce()
в этот раз. Следовательно, значением по умолчанию будет являться первый элемент в массиве.
Функция обратного вызова сначала проверяет, текущий ли элемент curr
больше текущего максимального значения max
. Если да, значение обновляется max
быть текущим элементом. Если это не так, max
не обновляется. Наконец, функция возвращает значение max
.
В этом случае reduce()
метод начнется с настройки max
до 5 и curr
до 20. Затем он проверит, есть ли 20 больше 5, поэтому он обновляется max
до 20
Затем он установится curr
до 100 и проверьте, 100 больше 20, то есть оно обновляется max
до 100
Он продолжит этот процесс до тех пор, пока не обработает все элементы в массиве. Окончательное значение max
будет максимальным значением в массиве, которое в данном случае равно 100.
Пример 3: Использование reduce()
чтобы объединить разные объекты в один объект:
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const obj3 = { e: 5, f: 6 };
const mergedObj = [obj1, obj2, obj3].reduce((acc, curr) => {
return { ...acc, ...curr };
}, {});
console.log(mergedObj); // { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 }
В этом примере у нас есть два аргумента acc
и curr
в функции обратного вызова The acc
представляет текущий объединенный объект, который был создан на данный момент, в то время как curr
представляет текущий объект, обрабатываемый в массиве.
Функция использует оператор распространения (...
), чтобы создать новый объект, объединяющий свойства текущего объединенного объекта acc
и текущий объект curr
. Затем он возвращает этот новый объект.
В этом случае reduce()
метод начнется с настройки acc
к пустому объекту (это значение, переданное как второй аргумент reduce()
). Затем он установится curr
к obj1
и создайте новый объект, объединяющий свойства пустого объекта и obj1
. Затем он установится curr
к obj2
и создать новый объект, сочетающий в себе свойства предыдущего объединенного объекта и obj2
. Он продолжит этот процесс, пока не обработает все объекты в массиве.
Окончательное значение acc
будет объединенным объектом, содержащим все свойства оригинальных объектов.
Пример 4: Использование reduce()
группировать объекты в массив. Например, группировка продуктов в корзине в соответствии с их торговой маркой.
const shoppingCart = [
{name: 'Apple', price: 1.99, quantity: 3},
{name: 'Apple', price: 1.99, quantity: 3},
{name: 'Xiomi', price: 2.99, quantity: 2},
{name: 'Samsung', price: 3.99, quantity: 1},
{name: 'Tesla', price: 3.99, quantity: 1},
{name: 'Tesla', price: 4.99, quantity: 4},
{name: 'Nokia', price: 4.99, quantity: 4},
]
const products = shoppingCart.reduce((productGroup, product) => {
const name = product.name;
if(productGroup[name] == null) {
productGroup[name] = [];
}
productGroup[name].push(product);
return productGroup;
}, {});
console.log(products);
// OUTPUT
{
Apple: [
{ name: 'Apple', price: 1.99, quantity: 3 },
{ name: 'Apple', price: 1.99, quantity: 3 }
],
Xiomi: [ { name: 'Xiomi', price: 2.99, quantity: 2 } ],
Samsung: [ { name: 'Samsung', price: 3.99, quantity: 1 } ],
Tesla: [
{ name: 'Tesla', price: 3.99, quantity: 1 },
{ name: 'Tesla', price: 4.99, quantity: 4 }
],
Nokia: [ { name: 'Nokia', price: 4.99, quantity: 4 } ]
}
В этом примере мы имеем shoppingCart
массив, представляющий разные продукты и два аргумента productGroup
и product
в функции обратного вызова
The productGroup
аргумент представляет текущую группу продуктов, найденных на данный момент, тогда как product
аргумент представляет текущий обрабатываемый продукт в массиве.
Функция сначала получает название текущего продукта, использующего product.name
. Затем он проверяет, существует ли группа для этого названия продукта в productGroup
объект с помощью if
заявление. Если нет, создается новая группа путем инициализации productGroup[name]
свойства к пустому массиву.
Наконец, функция выталкивает текущий продукт в группу с помощью push()
и возвращает обновленный productGroup
объект.
После reduce()
метод обработал все элементы в shoppingCart
массив, полученный productGroup
будет содержать ключи для каждого названия продукта и значения, которые являются массивами продуктов с таким названием.
Преимущества функций высшего порядка
Использование функций высшего порядка имеет некоторые важные преимущества для веб-разработчиков.
Во-первых, функции высшего порядка могут помочь улучшить разборчивость вашего кода, сделав его более лаконичным и легким для понимания. Это может помочь ускорить процесс разработки и упростить настройку кода.
Во-вторых, функции высшего порядка могут помочь организовать ваш код на меньшие фрагменты, облегчая его поддержку и расширение.
Вывод
В данной статье исследовано, что такое функция высшего порядка, преимущества его использования и как использовать его в практических программах.
Используя функции высшего порядка, веб-разработчики могут работать разумнее, организовывая свой код на меньшие части, делая его более понятным и более легким для отладки.
Теперь, когда вы пытаетесь использовать методы map(), filter() и reduce() и запутаетесь, просто помните следующее:
- Используйте map, когда вы хотите превратить массив
- Используйте фильтр для выбора подмножества данных из массива и
- Используйте уменьшение, если вы хотите вернуть одно значение как результат.
Для получения дополнительных сведений о функциях высшего порядка просмотрите это замечательное видео Акшая Саини на YouTube.