Прежде чем мы начнем и углубимся в функции высшего порядка. Позвольте мне задать вам вопрос.
Сколько из вас когда-либо использовали функции высшего порядка?
Для большинства из вас, ребята, которые долгое время работали над JavaScript или библиотекой, такой как React.
Ответ будет таким: Много / почти каждый день и продолжайте добавлять к этому, например: .map(), .reduce(), .filter() и .forEach() . Но что, если я спрошу вас, сколько из вас создали свою функцию высшего порядка? Тогда я получу на 50% меньше негативных отзывов, чем в первый раз.
Итак, давайте теперь начнем и напишем нашу собственную первую функцию высшего порядка.
Функция высшего порядка — это функция, которая получает функцию в качестве аргумента или возвращает функцию в качестве вывода.
Мы создадим функции более высокого порядка, чтобы выполнить некоторые вычисления для прямоугольной формы. Предположим, у нас есть прямоугольники разного размера, для этого нам нужно вычислить площадь, периметр, диагональ и т. д.
Допустим, у нас есть массив, который включает длину и высоту всех прямоугольников.
const rectangles = [{length: 10,height: 4},{length: 12,height: 6},{ length: 13,height: 3},{length: 8,height: 3}];
Теперь нам нужно вычислить площадь каждого прямоугольника и вывести только массив. Итак, большинство из нас сделает что-то вроде этого:
const area = rectangles.map((rectangle) => { return rectangle.length * rectangle.height; }); console.log(area); // [ 40, 72, 39, 24 ];
Теперь давайте посмотрим, как мы можем сделать нашу карту похожей на функцию высшего порядка:
const rectangles = [{length: 10,height: 4},{length: 12,height: 6},{ length: 13,height: 3},{length: 8,height: 3}]; const area = function(rectangles){ const output = []; for (let i = 0; i < rectangles.length; i++) { output.push(rectangles[i].length * rectangles[i].height); } return output; }; console.log(area(rectangles)); // [ 40, 72, 39, 24 ] const perimeter = function(rectangles){ const output = []; for (let i = 0; i < rectangles.length; i++) { output.push(2 * (rectangles[i].length + rectangles[i].height)); } return output; }; console.log(perimeter(rectangles)); // [ 28, 36, 32, 22 ]
В приведенном выше коде мы создали две функции для вычисления площади и периметра прямоугольников. (Примечание: это не функции высшего порядка, поскольку они не принимают функцию в качестве аргумента). Хотя это совершенно правильный код JavaScript, давайте еще раз проверим, чего не хватает в приведенном выше коде. Если вы поняли это правильно. Это повторение кода.
Мы повторяем:
const output = [];
for(let i = 0; i < rectangles.length; i++){}
и,
return output;
Почти каждая строка в обеих функциях одинакова, за исключением логики формулы. Что, если нам нужно больше вычислений над прямоугольниками? Что мы будем делать, так это копировать функции и просто менять логику. это сделает наш код уродливым и противоречит принципу DRY.
Давайте продолжим и сделаем приведенный выше код более функциональным, читабельным, оптимизированным и пригодным для повторного использования.
const calculate = function(rectangles, logic){ const output = []; for (let i = 0; i < rectangles.length; i++) { output.push(logic(rectangles[i])); } return output; }; const area = function({ length, height }){ return length * height; }; console.log(calculate(rectangles, area)) // [ 40, 72, 39, 24 ]
Выглядит чистым. Правильно?
Пройдемся по строчке:
- Во-первых, мы определили нашу общую функцию, которая называется
calculate
. Он принимает два аргументаrectangle
иlogic
. прямоугольники в нашем массиве и логика — это логика, которую мы хотим использовать для каждого прямоугольника. - И внутри цикла мы использовали логику, которую мы можем применить к каждому прямоугольнику.
- Мы абстрагировали нашу логику области от функции и передали в качестве параметра, который принимает длину и высоту прямоугольника способом деструктурирования объекта.
Теперь давайте посмотрим, хотим ли мы вычислить периметр прямоугольников с помощью приведенного выше кода.
const calculate = function(rectangles, logic){ const output = []; for (let i = 0; i < rectangles.length; i++) { output.push(logic(rectangles[i])); } return output; }; const area = function({ length, height }){ return length * height; }; const perimeter = function({ length, height }){ return 2 * (length + height); }; console.log(calculate(rectangles, area)) // Area: [ 40, 72, 39, 24 ] console.log(calculate(rectangles, perimeter)) // Perimeter: [ 28, 36, 32, 22 ]
Уууууу!! просто добавив 4 строки в приведенный выше код, мы также получим наш периметр.
Вы, должно быть, думаете, что этот парень такой Идиот. Тема была о функциях высшего порядка, но он затронул все (такие как DRY, многоразовые функции и т. д.), кроме HOF.
Да!! Ты прав. но при этом вы еще не поняли, что уже сделали свой первый HOF. Давайте вернемся на несколько шагов назад и проверим наш последний фрагмент кода. Кроме того, постарайтесь запомнить определение HOF.
Функция высшего порядка — это функция, которая получает функцию в качестве аргумента или возвращает функцию в качестве вывода.
И сейчас
const calculate = function(rectangles, logic){ const output = []; for (let i = 0; i < rectangles.length; i++) { output.push(logic(rectangles[i].length, rectangles[i].height)); } return output; };
Да!! Здесь это calculate
в нашей функции высшего порядка. который получает функцию logic
в качестве одного из аргументов.
[БОНУС]Дополнительно всегда здорово!! если вы получите что-то бесплатно. Давайте сделаем некоторые дополнительные вещи в приведенном выше коде. Если сравнить нашу функцию calculate
и функцию map
в Javascript.
console.log(calculate(rectangles, area)) // [ 40, 72, 39, 24 ] console.log(rectangles.map(area)) // [ 40, 72, 39, 24 ]
Эти две вещи делают одно и то же. Принимая функцию area
в качестве аргумента, перебирая все прямоугольники в массиве и возвращая новый массив площади. Но вызывающее представление отличается в обеих реализациях. В calculate
он принимает массив прямоугольников в качестве аргумента, но в map
он представлен как rectangles.map()
.
Давайте сделаем наш calculate
таким же, как map
Для этого вам просто нужно сделать одну простую вещь.
Array.prototype.calculate = function(logic) { const output = []; for (let i = 0; i < this.length; i++) { output.push(logic(this[i])); } return output; };
Вот и все. Итак, что мы сделали, так это добавили Array.prototype.calculate
вместо const calculate
и обработали наш прямоугольный объект внутри функции как this
.
Array.prototype
Это сделало функцию calculate
доступной для каждого доступного массива, и мы можем получить доступ к вычислению (HOF) для каждого массива, который мы определяем, например: обр. вычислить(‹наша логическая функция›).
Смотрите волшебство!!
const rectangles = [ { length: 10, height: 4 }, { length: 12, height: 6 }, {length: 13,height: 3,}, { length: 8, height: 3 }, ]; Array.prototype.calculate = function (logic) { const output = []; for (let i = 0; i < this.length; i++) { output.push(logic(this[i])); } return output; }; const area = function ({ length, height }) { return length * height; }; const perimeter = function ({ length, height }) { return 2 * (length + height); }; console.log(rectangles.calculate(area)); // [ 40, 72, 39, 24 ] console.log(rectangles.map(area)); // [ 40, 72, 39, 24 ]
Вывод. Функция высшего порядка проста в написании и реализации. И я уверен, что большинство из вас, должно быть, делали это долгое время, даже не подозревая об этом.