Композицията на функция е процесът на прилагане на функция към изхода на друга функция.

Ако сте разработчик на JavaScript, вероятно вече сте запознати с него или поне сте чували за него. Въпреки че функционалното програмиране е популярно в страната на JavaScript от доста време, все още има забележима липса на синтаксис за функционално програмиране в езика. Ако искате да композирате две функции, вие сте принудени да напишете своя собствена функция за композиране или да използвате вече наличните в библиотеки като Lodash и Ramda... или сте? Нека да разгледаме следния код:

„Това изобщо валиден ли е JavaScript?“, може да кажете. Краткият отговор е „да“ и не само това. Да погледнем дневника:

Работи точно както бихте очаквали да работи на език, който има оператор за композиция. Но JavaScript не... така че как беше направено? Нека разберем!

  1. Операторът-член

Има странно, но удобно свойство на оператора член в JavaScript: можете да имате толкова празно пространство около него, колкото искате. Това означава, че

obj.a

е същото като

obj . a

Което, както вероятно вече се досещате, означава, че е напълно подходящо да бъде маскирано като оператор за съставяне на функции. Но как да го претоварим?

2. Въведете проксито на ES6

Обектът Прокси се използва за дефиниране на персонализирано поведение за основни операции (напр. търсене на свойства, присвояване, изброяване, извикване на функция и т.н.).

Обектът Proxy е една от по-малко известните функции на ES6 и това е разбираемо — той е бавен, безполезен извън метапрограмиране и не е толкова блестящ като другите вградени обекти на ES6, като Promise и Map/Set.

Въпреки това е страхотно забавление за експериментиране! Да се ​​върнем към примера:

Прокси прихващането е основно претоварване на метод. За да изпълним примера по-горе, трябва да внедрим 2 капана: вземетеиприложетеединия. Прихващането get обработва достъпа до свойства, а прихващането apply обработва извиквания на функции. Първо, нека дефинираме функцията за прокси генератор:

Нашата първа задача е да можем да генерираме всяка функция в движение. За щастие, параметърът name, който виждате в gettrap, ни предоставя собствеността, която е достъпна. Когато има достъп до свойствата на картата или филтъра, вместо това ще върнем еквивалентните функции. Единственият завършек е да обвиете върнатата функция в compose, така че да можете да свързвате методите безкрайно.

(За действителните функции като картаи филтър, ще използвам Ramda, тъй като тези по подразбиране не са карирани.)

Капанът get е почти готов, сега можем да се съсредоточим върху това какво се случва, когато някоя от функциите бъде извикана. Прихващането за прилагане има 3 параметъра, но спокойно можем да игнорираме параметъра този и да помислим как можем да използваме другите два. target е функцията, която се извиква, а args са... добре, аргументите, с които е извикана. За да съставим функции, трябва да следим коя функция е била извикана и с какви аргументи, така че да можем да ги изпълним всички в края. Така че ще добавим втори аргумент към функцията за съставяне - такъв, който ще прехвърли съставената преди това функция към следващата.

Почти стигнахме! Единственото нещо, което ни липсва, е знак стоп, защото не знаем кога композицията спира и искаме истинския резултат вместо прокси обект. След известно бърникане го стесних до следния модел: функция се извиква като последната съставена функция и след това композицията се извиква с някои аргументи. Това, което имаме тук, са две последователни извиквания на функции. Знам, че това е доста ограничаващо, тъй като не можете да композирате функции, без да им предоставите някои аргументи, но кодът в тази публикация е повече за изследване на JavaScript, отколкото за изграждане на нещо полезно. Имайки предвид предишните открития, можем да проследим последователни извиквания на функции с друг аргумент към функцията за съставяне.

Ето кода в цялата му слава 🌟 (или е целият срам 😅)

Публикувах този фрагмент, за да можете да си поиграете с него и той също е в Github. Имайте предвид, че е много непълно и податливо на грешки, но заявките за изтегляне винаги се оценяват!

const { map, filter, find, groupBy } = require('composable-ramda')

Благодаря за четенето, надявам се, че сте научили нещо ново днес!

Ресурси

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy