Первый раз я столкнулся с функциональным программированием когда работал в Xiaomi.Тогда я читал разные композиционные коды, написанные начальником до этого, а потом какие-то инструментальные функции ramda.Это выглядело очень сложно, и тогда я попробовал я изо всех сил жалуюсь на функциональное программирование. Теперь я оглядываюсь на него. В то время я был очень недальновидным и просто хотел сказать: «Это действительно ароматно».
Я недавно изучал функциональное программирование, и я действительно чувствую, что мое мышление значительно улучшилось в процессе обучения, и мои способности к абстракции значительно улучшились, что заставило меня глубоко почувствовать прелесть функционального программирования. Поэтому я планирую использовать от 5 до 8 статей позже, чтобы подробно представить идею функционального программирования, основы, как проектировать, тестировать и т. д.
Сегодняшняя статья в основном знакомит с идеей функционального программирования.
- Работает ли функциональное программирование?
- Что такое функциональное программирование?
- Преимущества функционального программирования.
Объектно-ориентированное программирование (ООП) упрощает понимание кода за счет инкапсуляции изменений. Функциональное программирование (FP) упрощает понимание кода за счет минимизации изменений. -- Майкл Фезерс (Twitter)
Как мы все знаем, JavaScript — это динамический язык с большим количеством общих состояний, и со временем код становится настолько сложным, что становится громоздким и трудным в обслуживании. Объектно-ориентированный дизайн может помочь нам решить эту проблему в определенной степени, но этого недостаточно.
Поскольку состояний много, особенно важно обрабатывать поток данных и передачу изменений.Не знаю, знаете ли выреактивное программированиеПолезна ли эта парадигма программирования для работы с асинхронным ответом JavaScript или ответом на событие. В заключение, когда мы разрабатываем приложение, мы должны учитывать, соблюдаются ли следующие принципы проектирования.
- Расширяемость. Нужно ли мне постоянно реорганизовывать код для поддержки дополнительных функций?
- Простая модульность — если я изменю один файл, повлияет ли это на другой?
- Возможность повторного использования — много ли дублированного кода?
- Тестируемость. Беспокоит ли меня добавление модульных тестов к этим функциям?
- Разумный. Является ли код, который я пишу, сильно неструктурированным и трудным для понимания?
Я могу сказать вам это, как только вы изучите функциональное программирование, эти проблемы будут легко решены.Изначально идея была в функциональном программировании.Как только вы освоите функциональное программирование, а затем изучите реактивное программирование, понять его будет легче.Я испытал это на себе. сам. Когда я раньше изучал Rxjs, это было очень болезненно.Честно говоря, Rxjs — самая сложная библиотека, которую я когда-либо изучал, без исключения. После мучительного месяца или двух некоторые вещи все еще не работают вместе, что я считаю само собой разумеющимся, пока недавно не изучил функциональное программирование. Без преувеличения, я постараюсь познакомить вас с Rxjs в следующих статьях, я также поделился этой темой с компанией.
Что такое функциональное программирование?
Проще говоря, функциональное программирование — это стиль разработки программного обеспечения, в котором особое внимание уделяется использованию функций. Когда вы видите это предложение, я думаю, вы все еще в замешательстве. Вы не знаете, что такое функциональное программирование. Не волнуйтесь, я думаю, вы поймете, когда увидите его.
Еще одна вещь, которую следует иметь в виду, это то, что целью функционального программирования является использование функций дляАбстрактный поток управления и операции над данными, так что в системеустранить побочные эффектыиМинимизируйте изменения состояния.
Кратко продемонстрируем всю прелесть функционального программирования на примере.
Текущим требованием является вывод вывода на веб-страницу.“Hello World”
.
Может быть, новичок так и написал бы.
document.querySelector('#msg').innerHTML = '<h1>Hello World</h1>'
Эта программа очень проста, но весь код мертв и не может быть использован повторно.Если вы хотите изменить формат, содержание и т. д. сообщения, вам нужно переписать все выражение, чтобы его могли написать опытные фронтмены. конечные разработчики.
function printMessage(elementId, format, message) {
document.querySelector(elementId).innerHTML = `<${format}>${message}</${format}>`
}
printMessage('msg', 'h1', 'Hello World')
Это немного улучшает, но это все еще не повторно используемый фрагмент кода, если я пишу текст в файл, а не не-HTML, или я хочу повторить отображениеHello World
.
Итак, как бы вы написали этот код как функциональный разработчик?
const printMessage = compose(addToDom('msg'), h1, echo)
printMessage('Hello World')
Объясните этот код, гдеh1
иecho
функции,addToDom
Также очевидно, что это функция, так почему же мы пишем ее именно так? Похоже, что функций гораздо больше.
На самом деле речь идет о разложении программы на более повторно используемые, более надежные и простые для понимания части, а затем их объединении в более разумную программу в целом, что является основным принципом, о котором мы говорили ранее.
Compose кратко объясните, что он будет выполнять функцию последовательно от последнего параметра к первому параметру.Каждый параметр compose является функцией.Если вы не понимаете, вы можете проверить это.Это суть промежуточной части редукции.
Можно видеть, что мы являемся функцией разделения задачи на несколько мельчайших частиц, а затем выполнения нашей задачи путем ее объединения, что очень похоже на нашу идею компонентизации, разбивая всю страницу на несколько компонентов, а затем собирая ее для завершения. вся наша страница. В функциональном программировании композиция — очень, очень, очень важная идея.
Хорошо, давайте снова изменим требование, теперь нам нужно повторить текст три раза и вывести его в консоль.
var printMessaage = compose(console.log, repeat(3), echo)
printMessage(‘Hello World’)
Видно, что мы изменили требования и не изменили внутреннюю логику, а просто реорганизовали функцию.
Вы можете видеть, что функциональное программирование имеет декларативный паттерн в разработке. Чтобы полностью понять функциональное программирование, давайте сначала рассмотрим несколько основных концепций.
- декларативное программирование
- чистая функция
- Прозрачность котировок
- неизменность
декларативное программирование
Функциональное программирование — это парадигма декларативного программирования: эта парадигмаописать ряд операций, но нетпоказать, как они реализованыиликак потоки данных передают их.
Известный SQL-оператор — очень типичный пример декларативного программирования, состоящий из одного за другимописыватьКакая композиция утверждений должна быть в результате запроса, и реализован внутренний механизм извлечения данныхАннотация.
Давайте посмотрим на другой набор кода и сравним императивное программирование с декларативным.
// 命令式方式
var array = [0, 1, 2, 3]
for(let i = 0; i < array.length; i++) {
array[i] = Math.pow(array[i], 2)
}
array; // [0, 1, 4, 9]
// 声明式方式
[0, 1, 2, 3].map(num => Math.pow(num, 2))
Вы можете видеть, что императивы сообщают компьютеру, как именно выполнять определенную задачу.
И декларативность программыописание и оценкаотдельный. Он фокусируется на том, как использовать различныевыражениедля описания логики программы без обязательного указания изменений в ее потоке управления или отношениях состояний.
Почему мы хотим избавиться от циклов кода? Циклы являются важной структурой управления командами, но их трудно повторно использовать и вставлять в другие операции. Функциональное программирование, с другой стороны, направлено на то, чтобы максимально улучшить безгражданство и неизменность кода. Для этого научитесь использоватьНет побочных эффектовфункция, также называемая чистой функцией
чистая функция
чистая функцияникаких побочных эффектовФункция. Тот же вход имеет тот же результат, как и функция, которую мы ходили в школу.
Часто эти условия имеют побочные эффекты.
- Изменить глобальную переменную, свойство или структуру данных
- Изменить исходное значение параметра функции
- Обработка пользовательского ввода
- бросить исключение
- трафаретная печать или журнал
- Запрашивайте HTML-документы, файлы cookie браузера или получайте доступ к базам данных
Возьмем простой пример
var counter = 0
function increment() {
return ++counter;
}
Эта функция нечиста. Она считывает внешние переменные. Вы можете подумать, что в этом коде нет проблем, но нам нужно знать, что такие расчеты, основанные на внешних переменных, трудно предсказать. Вы также можете быть в другом Значение счетчика где-то изменен, так что значение, которое вы увеличиваете, не соответствует ожидаемому.
Чистая функция обладает следующими свойствами:
- Зависит только от введенных данных, а не от какого-либо скрытого или внешнего состояния, которое может измениться между вычислениями или вызовами функции.
- Не вызывает изменений вне области видимости, таких как изменение глобальных переменных или параметров, переданных по ссылке.
Но в нашей обычной разработке неизбежны некоторые побочные эффекты, взаимодействие с внешними системами хранения или DOM и т. д., но мы можем сделать их проще в управлении, отделив от основной логики.
Теперь у нас есть небольшое требование: найти запись студента по id и отрендерить ее в браузере (при написании программы подумайте, что она также может быть записана в консоль, базу данных или файл, поэтому подумайте, как сделать ваш код многоразовым) .
// 命令式代码
function showStudent(id) {
// 这里假如是同步查询
var student = db.get(id)
if(student !== null) {
// 读取外部的 elementId
document.querySelector(`${elementId}`).innerHTML = `${student.id},${student.name},${student.lastname}`
} else {
throw new Error('not found')
}
}
showStudent('666')
// 函数式代码
// 通过 find 函数找到学生
var find = curry(function(db, id) {
var obj = db.get(id)
if(obj === null) {
throw new Error('not fount')
}
return obj
})
// 将学生对象 format
var csv = (student) => `${student.id},${student.name},${student.lastname}`
// 在屏幕上显示
var append = curry(function(elementId, info) {
document.querySelector(elementId).innerHTML = info
})
var showStudent = compose(append('#student-info'), csv, find(db))
showStudent('666')
Если вы не понимаете карри, не волнуйтесь, это понятие сложно понять новичкам, и оно играет решающую роль в функциональном программировании.
Вы можете видеть, что функциональный код записывает showStudent как композицию небольших функций, уменьшая длину этих функций. Эта программа не идеальна, но уже может показать множество преимуществ перед императивом.
- гибкий. Есть три многоразовых компонента
- Декларативный стиль, обеспечивающий четкое представление высокоуровневых шагов и повышающий читабельность кода.
- Другой — отделить чистые функции от нечистого поведения.
Мы видим, что вывод чистых функций непротиворечив и предсказуем, и один и тот же ввод будет иметь одно и то же возвращаемое значение, что также называетсяПрозрачность котировок.
Прозрачность котировок
Ссылочная прозрачность — это правильный способ определить чистую функцию. Чистота в этом смысле представляет чистую связь отображения между аргументами функции и возвращаемым значением. Если функция всегда дает один и тот же результат для одних и тех же входных данных, мы говорим, что этоПрозрачность котировок.
Эту концепцию легко понять, достаточно привести два примера.
// 非引用透明
var counter = 0
function increment() {
return ++counter
}
// 引用透明
var increment = (counter) => counter + 1
На самом деле стрелочные функции имеют высокоуровневое название в функциональном программировании, называемое лямбда-выражениями.Такие анонимные функции академически называются лямбда-выражениями, и теперь они поддерживаются в Java.
неизменяемые данные
Неизменяемые данные — это данные, которые нельзя изменить после их создания. Как и во многих других языках, некоторые примитивные типы в JavaScript (String, Number и т. д.) по своей сути являются неизменяемыми, но объекты изменяются везде.
Рассмотрим простой код сортировки массива:
var sortDesc = function(arr) {
return arr.sort(function(a, b) {
return a - b
})
}
var arr = [1, 3, 2]
sortDesc(arr) // [1, 2, 3]
arr // [1, 2, 3]
Этот код, кажется, не проблема, но он вызовет побочные эффекты в процессе сортировки, изменив исходную ссылку, вы можете видеть, что исходная запись становится[1, 2, 3]
. Это недостаток языка, и как его преодолеть, будет описано далее.
Суммировать
- Код, использующий чистые функции, никогда не изменяет и не разрушает глобальное состояние, что помогает улучшить тестируемость и ремонтопригодность кода.
- В функциональном программировании используется декларативный стиль, о котором легко рассуждать и который улучшает читаемость кода.
- Функциональное программирование рассматривает функции как строительные блоки, используя первоклассные функции высшего порядка для улучшения модульности кода и возможности его повторного использования.
- Вы можете использовать реактивное программирование для объединения функций, чтобы уменьшить сложность программ, управляемых событиями (это может быть объяснено в отдельной статье позже).
Содержимое взято из «Руководства по функциональному программированию JavaScript».
Добро пожаловать, чтобы обратить внимание на личный публичный аккаунт [Front-end Taoyuan].Частота обновления публичного аккаунта выше, чем у Nuggets.