Вы когда -нибудь делали что -то, что похоже на этот шаблон?
const userInfoFromStorage = localStorage.getItem('userInfo')
const userInfoParsed = JSON.parse(userInfoFromStorage)
const userInfoClearedCache = { ...userInfoParsed, cache: {} }
return userInfoClearedCache
Много временных переменных в использовании. Я тоже делал это. Я бы придумал творческие способы назвать эти переменные, чтобы вроде «самообслуживания», что происходило. Но это, как правило, плохая идея, вот некоторые причины, почему:
- Чем больше переменных вы создаете, тем больше вероятность того, что вы получите опечатку.
- Операции, выполненные на данных, окружены большим количеством синтаксиса.
- Имена переменных не занимают место комментариев.
- Наименование ненужных переменных является ненужной умственной нагрузкой.
There are only two hard things in Computer Science: cache invalidation and naming things. -- Phil Karlton
Но что нам делать вместо этого? Очевидно, что это не будет легким кодом для работы:
return {
...(
JSON.parse(
localStorage.getItem(
'userInfo'
)
)
),
cache: {}
}
Икес! 😲
Несмотря на уродливое, приведенный выше код показывает, что можно выразить это преобразование как серию функциональных вызовов без переменных. Выход одной функции является входом следующей функции и т. Д. Мы хотим Значения труб между функциями Анкет Одним из решений является написание функции, которая позволяет нам внести эту абстракцию. Итак, как мы это сделаем?
Вот одно решение с использованием уменьшить :
const pipeline = ( initialValue, ...fns ) => (
fns.reduce(
( val, fn ) => fn( val ),
initialValue
)
)
Как видите, эта функция принимает ИСТИНАЛЬНАЯ ВАЛА и использует уменьшить Поддерживать выходной сигнал одной функции на вход следующей. Если вы не уверены, почему я использую здесь уменьшение, часть I моего Уменьшите учебник может быть полезным. Теперь мы можем рефакторировать исходный код, как SO:
return pipeline(
// get user information stored as a string in local storage
localStorage.getItem('userInfo'),
// parse the string
JSON.parse,
// reset the cache to an empty obj
obj => ({ ...obj, cache: {} })
)
Разве это не так чище? Легко увидеть, как данные текут сверху вниз.
Есть две общие проблемы, которые могут столкнуться с этим стилем, которые могут столкнуться, некоторые разработчики:
- Типы Как введите A
трубопроводфункция? - Регистрация (для отладки). Как вы регистрируете данные между цепочкой трубопроводов?
Мы рассмотрим эти вопросы здесь:
Существует способ выразить эту функцию, используя тип самореагирования, но это сложно и требует отдельной статьи. Для тех, кому любопытно, это то, на что будет выглядеть такой тип более или менее:
https://github.com/babakness/soultrain/blob/v0.0.43/src/type/_experiements.ts#L18
В качестве альтернативы мы можем просто использовать перегрузку функции TypeScript, чтобы выразить, как должен развиваться тип. Например:
function pipeline( a: A, ab: (a: A) => B ): B function pipeline( a: A, ab: (a: A) => B, bc: (a: B) => C ): C function pipeline( a: A, ab: (a: A) => B, bc: (a: B) => C, cd: (c: C) => D):D // and so on
По сути, это трубопровод работает в моей библиотеке Soultrain.
Babakness/Soultrain
Soultrain – это компактная функциональная библиотека, написанная в TypeScript.
Обратите внимание, что эта библиотека по -прежнему экспериментальна, и будут нарушать изменения. Если вы пинаете шины по этому в рамках другого экспериментального проекта, лучше всего заблокировать их до определенной версии.
NPM установить Soultrain
Soultrain – это компактная функциональная библиотека, написанная в TypeScript. Он вдохновлен RAMDA и контейнерными алгебраическими данными на основе программирования.
Ramda – отличный инструмент, однако, он опирается на спецификации комментариев JS DOC для предоставления данных типа. В то время как это хорошо, TypeScript обеспечивает превосходное статическое значение. Таким образом, эта библиотека направлена на то, чтобы обеспечить общие цели функциональных инструментов с гораздо лучшим статическим тип.
Этот раздел будет завершен позже. Из высокого уровня библиотека предоставляет Smart карри , труба и трубопровод функции с хорошей поддержкой типа. В настоящее время он предоставляет две монады, a Может и Транссущество Анкет Первые работы, аналогичные другими, возможно, библиотеками, однако, он обеспечивает…
Преимущество печатной версии заключается в том, чтобы компилятор дважды проверил код. Вот пример того, что версия JavaScript не поймает:
Компилятор заметил, что Roo не является свойством на объекте, возвращенном Процессор.process
Чтобы записать данные, проходящие между функциями в трубопроводе, можно просто использовать функцию журнала, которая входит в систему и возвращает полученные данные. С типами это может быть написано как таковое:
const log = (data: A): A => (console.log(data),data)
Или, чтобы войти с сообщением, можно определить журнал как это:
const noteLog = (note: unknown) => ( (data: A): A => ( console.log(note, data), data ) )
Который можно использовать таким образом:
return pipeline(
// get user information stored as a string in local storage
localStorage.getItem('userInfo'),
// parse the string
JSON.parse,
// log the data,
noteLog('data before cache removal'),
// reset the cache to an empty obj
obj => ({ ...obj, cache: {} })
)
В качестве упражнения для читателя можно также создать функцию, которая условно запускает отладчика.
трубопровод Функция, нетерпеливый брат труба и Составьте , пригласит вас написать больше функций. Это также продемонстрирует вам, насколько мощным может быть карри и даже сообщите вам о заказе, которые должны быть ваши параметры функции.
Чтобы проиллюстрировать это, обратите внимание на функцию стрелки в нашем примере трубопровода. Не obj одноразовая переменная? Все, для чего мы его используем, это в качестве заполнителя для наших данных … всего лишь несколько персонажей справа!
Оказывается, что, следя за тем, чтобы наши исходные данные были последним параметром, и, используя карри, мы можем еще больше упростить наш код. Ниже я написал, как это можно выразить в Vanilla JS-Notice, которую мы хотим переопределить ключи для входящего объекта. Это будет второй параметр-таким образом, движется слева направо, переопределяя второй объект, obj2 , с объектом в первом параметре, obj1 Анкет
Так что вместо размещения obj2 Справа от разброса объекта, мы переоцениваем порядок и помещаем его слева:
const mergeLeft = curry(
// spread the second parameter first
( obj1, obj2 ) => ({ ...obj2, ...obj1 })
)
Если вы не знакомы с карри , это в основном изменяет нашу функцию так, чтобы ее можно было использовать так, как если бы она была написана таким образом:
const mergeLeft = obj1 => obj2 => ({ ...obj2, ...obj1 })
Теперь наше решение становится:
return pipeline(
// get user information stored as a string in local storage
localStorage.getItem('userInfo'),
// parse the string
JSON.parse,
// log the data,
noteLog('data before cache removal'),
// reset the cache to an empty obj
mergeLeft({ cache: {} })
)
Piping побуждает нас писать небольшие, повторные функции, которые выполняют определенные задачи и которые принимают исходные данные в качестве последнего параметра. Это похоже на команды на терминале UNIX или Linux. Это функциональная концепция программирования, которая существует уже давно. И, как отличная классика, это принцип, который со временем оказывается лучше.
Данные трубопровода между функциями являются отличной альтернативой созданию одноразовых переменных, которые используются только для передачи данных из одной функции в другую. Многие языки программирования распознают это и имеют оператора для выполнения этой задачи. Для JavaScript есть предложенный оператор трубопровода
TC39/Prefosal-Pipeline-Operator
Предложение о добавлении простого, но используемого оператора трубопровода в JavaScript.
Это предложение представляет нового оператора |> Похоже на F# Ocaml Эликсир Вяз , Юлия , Взломать и Livescript , а также трубы Unix и Хаскелл S & Анкет Это обратно-совместимый способ оптимизации цепных функциональных вызовов в читаемой, функциональной форме и обеспечивает практическую альтернативу расширению встроенных прототипов.
Эти предложения следующие:
- F# трубопроводы : Объясните + Технические характеристики
- Умные трубопроводы : Объясните + Технические характеристики
Вавилочные плагины Для обоих уже ведутся сборы отзывов.
Смотрите также Последняя презентация TC39 а также Недавние проблемы GitHub …
Что позволило бы нам переписать наш первоначальный пример, как это:
return (
// get user information stored as a string in local storage
localStorage.getItem('userInfo'),
// parse the string
|> JSON.parse
// reset the cache to an empty obj
|> obj => ({ ...obj, cache: {} })
)
До тех пор мы можем извлечь выгоду из использования трубопровод Функция сегодня, чтобы избежать ненужных объявлений переменных.
Оригинал: “https://dev.to/babak/use-pipeline-avoid-unnecessary-variables-for-better-data-flow-54m2”