Чем больше вы знаете, тем больше вы не знаете
点赞
Посмотри еще раз, аромат остался в руке, и слава
введение
Композиция функций называется композицией в функциональном программировании, и мы поймем концепцию композиции и изучим множество примеров. затем создайте свой собственныйcompose
функция.
Концепция комбинации очень интуитивно понятна, а не функциональное программирование, а можно увидеть в нашей жизни или в предельном развитии.
Например, наше популярное SPA (одностраничное приложение) будет иметь концепцию компонентов.Почему у нас есть концепция компонентов, потому что ее цель состоит в том, чтобы позволить вам абстрагировать некоторые общие функции или комбинации элементов в повторно используемые компоненты, даже если это не так. Универсальный При создании сложной страницы вы также можете разделить ее на компоненты с простыми функциями, а затем объединить их в страницы, отвечающие вашим различным потребностям.
По сути, функциональная композиция похожа на функциональную композицию — это процесс объединения простых задач, которые были декомпозированы на сложные задачи.
что такое комбинация
Давайте рассмотрим команду, обычно используемую в системах Linux.ps -ef | grep node
Целью этой команды является отображение связанных с узлом процессов в системе, среди которыхps -ef
это полный формат, показывающий все процессы,grep node
заключается в фильтрации содержимого, связанного с узлом,|
это функция, которая отправляет выходные данные функции слева в качестве входных данных для функции справа.
Этот пример может быть тривиальным, но он передает идею:
Вывод каждой программы может быть вводом другой программы, которая еще не известна.
Согласно нашему пониманию композиции, теперь предполагается, что мы имеемcompose
Функция может выполнять следующие функции:
function compose(...fns){
//忽略
}
// compose(f,g)(x) === f(g(x))
// compose(f,g,m)(x) === f(g(m(x)))
// compose(f,g,m)(x) === f(g(m(x)))
// compose(f,g,m,n)(x) === f(g(m(n(x))))
//···
Мы видим, чтоcompose
Функция получит несколько функций в качестве параметров, и вывод каждой функции после выполнения используется в качестве вывода следующей функции, пока вывод последней функции не будет использован в качестве конечного результата.
Применить функцию создания
в создании и совершенствовании собственногоcompose
Перед функцией давайте научимся ее применятьcompose
функция.
Предположим, есть необходимость округлить заданное число, которое является символьным типом.
Регулярная реализация:
let n = '3.56';
let data = parseFloat(n);
let result = Math.round(data); // =>4 最终结果
В этом коде вы можете увидетьparseFloat
Вывод функции передается в качестве входных данныхMath.round
функция для получения конечного результата, которыйcompose
Типичные проблемы, которые могут решить функции.
использоватьcompose
Переписать функцию:
let n = '3.56';
let number = compose(Math.round,parseFloat);
let result = number(n); // =>4 最终结果
Ядро этого кода проходит черезcompose
БудуparseFloat
а такжеMath.round
объединить вместе, чтобы вернуть новую функциюnumber
.
Этот процесс композиции является функциональной композицией! Мы объединяем две функции вместе, чтобы новая функция могла быть построена как раз вовремя!
В качестве другого примера предположим, что у нас есть две функции:
let splitIntoSpaces = str => str.split(' ');
let count = array => array.length;
Теперь я хочу создать новую функцию для подсчета количества слов в строке Это можно сделать легко:
let countWords = compose(count,splitIntoSpaces);
Назови это:
let result = countWords('hello your reading about composition'); // => 5
Полезность композиции в развитии
Предположим, у нас есть такое требование: дать вам строку, преобразовать строку в верхний регистр, а затем изменить порядок.
Наше общее мнение таково:
let str = 'jspool'
//先转成大写,然后逆序
function fn(str) {
let upperStr = str.toUpperCase()
return upperStr.split('').reverse().join('')
}
fn(str) // => "LOOPSJ"
Этот код работает нормально, но теперь требования были изменены, чтобы распаковать и упаковать каждый символ в массив после капитализации строки:
"jspool" => ["J","S","P","O","O","L"]
Чтобы достичь этой цели, нам нужно изменить функцию, которую мы инкапсулировали ранее, что фактически нарушает принцип открытого-закрытого в шаблоне проектирования.
Принцип открытости-закрытости: объекты (классы, модули, функции и т. д.) в программном обеспечении должны быть открыты для расширения, но закрыты для модификации.
Итак, когда требования не изменились, а строки по-прежнему пишутся с заглавной буквы и наоборот, как использовать идею комбинирования для записи?
Исходное требование, мы можем достичь этого:
let str = 'jspool'
function stringToUpper(str) {
return str.toUpperCase()
}
function stringReverse(str) {
return str.split('').reverse().join('')
}
let toUpperAndReverse = compose(stringReverse, stringToUpper)
let result = toUpperAndReverse(str) // "LOOPSJ"
Затем, когда нам нужно изменить строку на верхний регистр и разбить ее на массив, нам вообще не нужно изменять ранее инкапсулированную функцию:
let str = 'jspool'
function stringToUpper(str) {
return str.toUpperCase()
}
function stringReverse(str) {
return str.split('').reverse().join('')
}
function stringToArray(str) {
return str.split('')
}
let toUpperAndArray = compose(stringToArray, stringToUpper)
let result = toUpperAndArray(str) // => ["J","S","P","O","O","L"]
Видно, что при изменении требований мы не ломали ранее инкапсулированный код, а только добавляли функции, а потом функции рекомбинировали.
У кого-то могут возникнуть сомнения, когда код пишется комбинационным способом, когда меняются требования, код все равно модифицируется, это тоже не нарушение принципа открытости-закрытости? По сути, мы модифицируем логический код вызова, а не модифицируем инкапсулированный и абстрагированный код, и этот метод написания также отстаивается по принципу открыто-закрыто.
Предположим, что мы снова изменили требования.Текущее требование состоит в том, чтобы перехватить первые 3 символа после преобразования строки в верхний регистр, а затем преобразовать ее в массив, тогда мы можем реализовать это следующим образом:
let str = 'jspool'
function stringToUpper(str) {
return str.toUpperCase()
}
function stringReverse(str) {
return str.split('').reverse().join('')
}
function getThreeCharacters(str){
return str.substring(0,3)
}
function stringToArray(str) {
return str.split('')
}
let toUpperAndGetThreeAndArray = compose(stringToArray, getThreeCharacters,stringToUpper)
let result = toUpperAndGetThreeAndArray(str) // => ["J","S","P"]
Из этого примера мы можем узнать, что способ композиции на самом деле заключается в абстрагировании функций одной функции, а затем в составлении сложных функций, что не только делает логику кода более понятной, но и значительно упрощает обслуживание.
достичь комбинации
оглядыватьсяcompose
Что именно делает функция:
// compose(f,g)(x) === f(g(x))
// compose(f,g,m)(x) === f(g(m(x)))
// compose(f,g,m)(x) === f(g(m(x)))
// compose(f,g,m,n)(x) === f(g(m(n(x))))
//···
В двух словах, он принимает несколько функций в качестве параметров и возвращает новую функцию. Когда новая функция выполняется, согласно由右向左
Порядок оформления поступающихcompose
Функции в , результат выполнения каждой функции используется в качестве ввода следующей функции, пока вывод последней функции не используется в качестве окончательного результата вывода.
еслиcompose
Количество функций, полученных функцией, фиксировано, поэтому реализация очень проста и простая для понимания.
Принимает только два параметра:
function compose(f,g){
return function(x){
return f(g(x));
}
}
Принимаются только три параметра:
function compose(f,g,m){
return function(x){
return f(g(m(x)));
}
}
В приведенном выше коде нет проблем, но мы должны учитывать следующее.compose
Количество принимаемых параметров неизвестно, рассматриваем использование остальных параметров для получения:
function compose(...fns){
return function(x){
//···
}
}
Сейчасcompose
полученные параметрыfns
является массивом, то теперь возникает вопрос, как объединить функции в массиве.从右至左
Выполнять последовательно.
Мы выбираем массив изreduceRight
функция для реализации:
function compose(...fns){
return function(x){
return fns.reduceRight(function(arg,fn){
return fn(arg);
},x)
}
}
Так мы достиглиcompose
функция~
Реализовать конвейер
compose
Поток данных从右至左
, потому что самая правая функция выполняется первой, а самая левая функция выполняется последней!
но некоторым нравится从左至右
Метод выполнения , то есть самая левая функция выполняется первой, а самая правая функция выполняется последней!
Процесс обработки потока данных слева направо называется конвейером!
管道(pipeline)
осуществление того жеcompose
Реализация очень похожа, потому что единственная разница между ними заключается в направлении потока данных.
В сравненииcompose
Реализация функции требует толькоreduceRight
заменитьreduce
Только что:
function pipe(...fns){
return function(x){
return fns.reduce(function(arg,fn){
return fn(arg);
},x)
}
}
а также组合
Некоторые люди предпочитают管道
. Это просто личное предпочтение и не имеет ничего общего с базовой реализацией. Дело в томpipe
а такжеcompose
Делать то же самое — это просто другой выпуск потока данных! Мы можем использовать в кодеpipe
илиcompose
, но не оба, так как это может вызвать путаницу среди членов команды. Если вы собираетесь его использовать, придерживайтесь только одной комбинации стилей.
Рекомендуемая серия статей
- Анализ и реализация одностраничной маршрутизации «переднего плана»
- «Front-end Advanced» полностью понимает каррирование функций.
- Память кучи памяти стека "Front-end advanced" в JS
- «Расширенное переднее» управление памятью в JS
- Массив "Front-end advanced" вышел из строя
Ссылаться на
напиши в конце
- Если в статье есть ошибки, исправьте их в комментариях, если статья вам поможет, добро пожаловать
点赞
а также关注
- Эта статья была впервые опубликована одновременно сgithub, доступны наgithubНайдите больше отличных статей в
Watch
&Star ★
- Для последующих статей см.:строить планы
Добро пожаловать в публичный аккаунт WeChat
【前端小黑屋】
, 1–3 высококачественные высококачественные статьи публикуются каждую неделю, чтобы помочь вам в продвижении вперед.